29 de marzo de 2026

Claude Code: Custom Commands — Tus propios slash commands

Hasta ahora en esta serie hemos visto Hooks, que garantizan cómo se comporta el agente, y Skills, que definen qué sabe el agente. En este artículo vemos el tercer pilar de la extensibilidad de Claude Code: los Custom Commands, que definen qué puede hacer el agente cuando tú se lo pides explícitamente.

La distinción con las Skills es importante y vale la pena tenerla clara desde el principio. Una Skill se activa automáticamente cuando el agente detecta que la tarea actual es relevante; tú no tienes que hacer nada. Un Custom Command se activa cuando tú escribes /nombre — es una decisión consciente del developer, no del agente. Eso los hace perfectos para flujos de trabajo repetitivos que siempre quieres ejecutar de la misma forma, en el momento que tú decides.

En este artículo cubrimos la anatomía completa de un comando, el sistema de argumentos con $ARGUMENTS y posicionales, el frontmatter avanzado, cómo ejecutar shell desde dentro de un comando, los namespaces, la selección de modelo por comando, la integración con Tasks para workflows multi-paso, y los 5 ejemplos prácticos de la serie.

Sin más, vamos al tema.


Commands vs. Skills: cuándo usar cada uno

La confusión entre Commands y Skills es comprensible porque ambos usan Markdown y ambos extienden las capacidades del agente. La diferencia está en quién decide cuándo activarlos.

CaracterísticaCustom CommandSkill
Activación Tú escribes /nombre Claude detecta automáticamente por contexto
Control Total — ocurre cuando tú decides Delegado al modelo
Argumentos Sí — $ARGUMENTS, $1, $2 No directamente
Ideal para Flujos de trabajo repetitivos con pasos definidos: commits, scaffolding, análisis específicos Conocimiento de dominio que aplica en múltiples contextos: convenciones, patrones, guías
Estructura Un archivo .md Un directorio con SKILL.md, scripts, templates, referencias
Ubicación .claude/commands/ o ~/.claude/commands/ .claude/skills/ o ~/.claude/skills/
Una forma de pensarlo: las Skills son el conocimiento del agente; los Commands son su lista de tareas. "Sé cómo hacer TDD en Spring Boot" es una Skill. "Haz este commit ahora siguiendo Conventional Commits" es un Command.

Anatomía de un Custom Command

Un Custom Command es un archivo Markdown guardado en .claude/commands/. El nombre del archivo (sin la extensión) se convierte en el slash command. Un archivo llamado scaffold.md se invoca con /scaffold.

.claude/commands/commit.md
Frontmatter YAML — opcional pero muy útil
---
description: Genera un commit con mensaje Conventional Commits
argument-hint: [tipo] [descripción opcional]
allowed-tools: Bash
model: haiku
---
Cuerpo Markdown — las instrucciones
# Commit con Conventional Commits
 
Genera y ejecuta un git commit siguiendo el estándar
Conventional Commits para los cambios actuales.
 
El tipo de commit es: $1
La descripción adicional (si se proporcionó) es: $2
 
Pasos:
1. Ejecuta `git diff --staged` para ver los cambios
2. Analiza los cambios y genera un mensaje descriptivo
3. Formato: tipo(scope): descripción en imperativo
4. Ejecuta el commit

Cuando ejecutas /commit feat "agrega validación de email", Claude lee el archivo, sustituye $1 por feat y $2 por agrega validación de email, y ejecuta las instrucciones con ese contexto.


El sistema de argumentos

Hay tres formas de usar argumentos en un comando, cada una con su caso de uso específico.

$ARGUMENTS — todos los argumentos como una cadena

La forma más simple: todo lo que escribas después del nombre del comando se inyecta como texto en $ARGUMENTS.

# .claude/commands/explain.md
Explica en detalle qué hace el siguiente código Java,
incluyendo complejidad algorítmica si aplica:
 
$ARGUMENTS
# Uso:
/explain public List<User> findActiveUsers() { return repo.findByActiveTrue(); }

$1, $2, $3 — argumentos posicionales

Cuando el comando tiene estructura definida y necesitas separar los argumentos por posición. Los argumentos se separan por espacios; los que contienen espacios van entre comillas.

# .claude/commands/scaffold-service.md
Genera la estructura completa de un servicio Spring Boot.
 
Nombre del servicio: $1
Módulo donde va: $2
Descripción de lo que hace: $3
 
Crea:
- La interfaz $1Service en src/main/java/.../services/
- La implementación $1ServiceImpl
- El test unitario $1ServiceTest con JUnit 5 y Mockito
- El request/response DTO correspondiente
# Uso:
/scaffold-service Payment payments "Procesa pagos con tarjeta de crédito"

$ARGUMENTS condicional — un comando con múltiples modos

Una de las técnicas más poderosas: un solo comando que se comporta diferente según el argumento recibido. Combinando $ARGUMENTS con instrucciones condicionales en el prompt se pueden crear comandos versátiles donde /review security y /review performance activan análisis completamente diferentes desde el mismo archivo.

# .claude/commands/review.md
---
description: Análisis de código — modo según argumento
argument-hint: security | performance | architecture | all
---
 
Analiza el diff actual (git diff main...HEAD) con el siguiente foco:
 
$ARGUMENTS
 
Instrucciones según el foco:
- Si es "security": busca SQL injection, XSS, secrets hardcodeados,
  endpoints sin autenticación y configuraciones inseguras de Spring Security
- Si es "performance": busca queries N+1, FetchType.EAGER en colecciones,
  operaciones síncronas bloqueantes en Spring WebFlux, y memory leaks
- Si es "architecture": busca violaciones de capas, acoplamiento circular,
  clases con múltiples responsabilidades y dependencias hacia adentro
- Si es "all" o sin argumento: corre los tres análisis anteriores
# Los tres modos desde el mismo archivo:
/review security
/review performance
/review architecture
/review          # sin argumento → modo "all"

Frontmatter avanzado

El frontmatter YAML es opcional, pero marca la diferencia entre un comando básico y uno profesional. Estos son todos los campos disponibles:

CampoTipoDescripción
description string Aparece en /help y en el autocompletado. Describe qué hace el comando.
argument-hint string Texto de ayuda que aparece al escribir el comando. Describe qué argumentos acepta.
allowed-tools string Herramientas disponibles durante la ejecución. Limita el scope sin pedir confirmación.
model string Modelo a usar para este comando específico: haiku, sonnet, opus.
---
description: Genera el changelog entre dos tags de Git
argument-hint: [tag-anterior] [tag-nuevo]
allowed-tools: Bash
model: haiku
---
argument-hint en el autocompletado: Cuando el usuario escribe / en la sesión, Claude Code muestra la lista de comandos disponibles con su description. Cuando empieza a escribir el nombre del comando, muestra el argument-hint. Estos dos campos juntos convierten tus comandos en herramientas autodocumentadas.

Ejecutar shell desde un comando: el prefijo !

Esta es la capacidad más poderosa y menos conocida de los Custom Commands: puedes ejecutar comandos de shell dentro del archivo Markdown del comando usando el prefijo !. El output del comando se inyecta en el contexto antes de que Claude empiece a procesar las instrucciones.

# .claude/commands/commit.md
# El ! ejecuta el comando y vuelca el output al contexto
---
description: Genera y ejecuta un commit con Conventional Commits
allowed-tools: Bash
model: haiku
---
 
Genera un commit para los siguientes cambios staged:
 
!git diff --staged
!git status --short
 
Usa el estándar Conventional Commits:
- Tipo: feat | fix | refactor | test | docs | chore | perf
- Formato: tipo(scope): descripción en imperativo (max 72 chars)
- Si hay múltiples cambios de distintos tipos, haz un commit por tipo
 
Después de generar el mensaje, ejecútalo con git commit.

La diferencia con pedirle al agente que ejecute git diff --staged es que el shell se ejecuta antes de que el agente empiece a pensar. El agente recibe el output como parte del prompt inicial, no como resultado de una herramienta que tuvo que invocar. Esto lo hace más rápido y consume menos tokens.

El ! en comandos vs. el ! en la sesión: El ! dentro de un archivo .md de comando ejecuta el shell cuando el comando se invoca y vuelca el output al contexto inicial. El ! que escribes directamente en la sesión interactiva ejecuta el shell en ese momento y vuelca el output a la conversación activa. Mismo prefijo, mismo efecto, diferente momento de ejecución.

Ubicaciones y namespaces

Los Custom Commands tienen dos alcances, igual que las Skills, y Claude Code los distingue con un sistema de namespaces:

Scope del proyecto (.claude/commands/):
→ Se invoca como /nombre o /project:nombre
→ Se versiona en Git con el proyecto
→ Disponible para todo el equipo

Scope personal (~/.claude/commands/):
→ Se invoca como /user:nombre
→ No se versiona
→ Disponible en todos tus proyectos

Namespacing por subdirectorios:
.claude/commands/git/commit.md → /git:commit
.claude/commands/git/branch.md → /git:branch
.claude/commands/db/migrate.md → /db:migrate

Los subdirectorios dentro de .claude/commands/ crean namespaces automáticamente. Esto es muy útil cuando tienes muchos comandos: en lugar de una lista plana de 20 comandos, los organizas en grupos temáticos que el autocompletado presenta de forma organizada.

# Estructura recomendada para proyectos con muchos comandos
.claude/commands/
├── git/
│   ├── commit.md       → /git:commit
│   ├── branch.md       → /git:branch
│   └── pr.md           → /git:pr
├── gen/
│   ├── service.md      → /gen:service
│   ├── controller.md   → /gen:controller
│   └── migration.md    → /gen:migration
├── fix/
│   ├── tests.md        → /fix:tests
│   └── build.md        → /fix:build
└── review.md           → /review
Tip de naming: Usar prefijos temáticos como review-, gen-, fix- o la organización por subdirectorios hace que el autocompletado con / muestre los comandos agrupados, lo que facilita encontrarlos rápido incluso cuando tienes más de 10.

Selección de modelo por comando

Una de las funcionalidades más valiosas del frontmatter es la selección de modelo. No todas las tareas necesitan el mismo nivel de inteligencia, y usar el modelo correcto para cada tarea puede hacer una diferencia enorme en velocidad y costo.

ModeloCuándo usarlo en un comandoEjemplo
haiku Tareas mecánicas y repetitivas: formatear commits, generar nombres de ramas, crear boilerplate simple /commit, /branch, /changelog
sonnet Tareas de implementación estándar: scaffolding de servicios, generación de tests, refactorizaciones acotadas /gen:service, /fix:tests
opus Análisis complejos: revisiones de arquitectura, análisis de seguridad, debugging de problemas difíciles /review architecture, /security-audit
# Comando rápido con Haiku — responde en segundos
---
description: Crea una rama con nombre estándar del equipo
argument-hint: descripcion-del-feature
model: haiku
allowed-tools: Bash
---
Crea una rama Git con el nombre estándar del equipo para: $ARGUMENTS
 
Formato: feature/PROJ-NNN-descripcion-en-kebab-case
Si no hay número de ticket en la descripción, usa feature/descripcion.
Ejecuta: git checkout -b [nombre-generado]

Integración con Tasks: workflows multi-paso

Los Custom Commands pueden orquestar flujos de trabajo complejos que implican múltiples pasos, archivos y decisiones. La forma más efectiva de hacerlo es estructurando el comando como una lista de Tasks que el agente ejecuta secuencialmente, con puntos de verificación entre cada una.

# .claude/commands/gen/feature.md
# Scaffolding completo de un feature — ejecuta múltiples pasos con verificación
---
description: Genera el scaffolding completo de un feature nuevo
argument-hint: [nombre-del-feature] [modulo]
allowed-tools: Read, Write, Bash
---
 
Genera el scaffolding completo para el feature "$1" en el módulo "$2".
 
## Task 1: Análisis previo
Antes de crear ningún archivo:
- Lee la estructura actual del módulo $2 en src/main/java
- Identifica las convenciones de naming existentes
- Lista los archivos que crearás (pide confirmación antes de continuar)
 
## Task 2: Estructura de capas
Crea los archivos en este orden exacto:
1. Entity / Domain object
2. Repository interface
3. Service interface + implementación
4. Controller REST
5. Request/Response DTOs
 
Sigue las convenciones identificadas en Task 1.
 
## Task 3: Tests
Para cada clase creada, genera el test correspondiente:
- Tests unitarios con Mockito para servicios
- Tests de integración con Testcontainers para repositorios
 
## Task 4: Verificación
- Compila: ./gradlew compileJava
- Corre los tests nuevos: ./gradlew test --tests "*$1*"
- Reporta qué pasó y qué queda pendiente

La clave de este patrón es que cada Task tiene un objetivo claro y verificable. Si Task 1 falla (por ejemplo, el módulo no existe), el agente lo reporta antes de crear archivos. Si Task 4 falla, el agente tiene el contexto completo para diagnosticar qué salió mal.


5 ejemplos prácticos

Ejemplo 1 (Java / Gradle): Commit con Conventional Commits

El comando más usado en el día a día. Usa Haiku (rápido y económico), ejecuta git diff --staged automáticamente y genera el mensaje sin que tengas que copiar nada.

# .claude/commands/git/commit.md
---
description: Genera y ejecuta un commit con Conventional Commits
allowed-tools: Bash
model: haiku
---
 
Genera un commit para estos cambios:
 
!git diff --staged
!git status --short
 
Reglas:
- Formato: tipo(scope): descripción en imperativo (max 72 chars)
- Tipos: feat | fix | refactor | test | docs | chore | perf | ci
- El scope es el módulo o paquete Java afectado (en minúsculas)
- Si hay breaking change, añade "!" después del tipo: feat!:
- Si hay múltiples tipos de cambios, propón splits en commits separados
 
Cuando tengas el mensaje, ejecuta el commit.
Si hay cambios sin stage, avisa antes de proceder.
# Uso: simplemente invoca el comando — no necesitas argumentos
/git:commit

Ejemplo 2 (Java / Gradle): Scaffolding de servicio Spring Boot

Genera la estructura completa de un servicio — interfaz, implementación, test — siguiendo las convenciones del proyecto. Acepta argumentos posicionales para el nombre y módulo.

# .claude/commands/gen/service.md
---
description: Genera interfaz, implementación y test de un servicio Spring Boot
argument-hint: NombreServicio modulo "descripción"
allowed-tools: Read, Write, Bash
---
 
Genera la estructura completa del servicio "$1" en el módulo "$2".
Descripción de lo que hace: $3
 
Antes de crear nada:
- Lee el directorio src/main/java para identificar el package base
- Verifica si existe ya el módulo $2 y sus convenciones
 
Crea en orden:
1. Interfaz: $1Service.java
2. Implementación: $1ServiceImpl.java con @Service y @RequiredArgsConstructor
3. Test: $1ServiceTest.java con @ExtendWith(MockitoExtension.class)
 
Convenciones obligatorias:
- Inyección por constructor (no @Autowired en campos)
- Lombok para boilerplate (@RequiredArgsConstructor, @Slf4j)
- Métodos del test: nombreMetodo_condicion_resultadoEsperado()
 
Al terminar: ./gradlew compileJava para verificar que compila.
/gen:service Payment payments "Procesa pagos con tarjeta de crédito y PayPal"

Ejemplo 3 (Java / Gradle): Fix automático de tests fallidos

Ejecuta los tests, captura los fallos y le pide al agente que los corrija en una sola invocación. Útil después de una refactorización o cuando el build de CI está roto.

# .claude/commands/fix/tests.md
---
description: Corre los tests, analiza los fallos y los corrige
argument-hint: [patrón de test opcional]
allowed-tools: Read, Write, Bash
---
 
!./gradlew test $ARGUMENTS 2>&1 | tail -60
 
Analiza los tests fallidos del output anterior y corrígelos.
 
Proceso:
1. Identifica la causa raíz de cada fallo (¿cambio en la API?, ¿dato de prueba roto?, ¿bug real?)
2. Distingue entre: test que falló por cambio legítimo de comportamiento vs. bug introducido
3. Si es cambio legítimo: actualiza el test para reflejar el nuevo comportamiento correcto
4. Si es bug: corrige el código de producción, no el test
5. Vuelve a correr los tests para confirmar que todos pasan
 
No hagas commit — solo corrije y verifica.
# Correr todos los tests fallidos:
/fix:tests
 
# Solo los tests de un módulo específico:
/fix:tests --tests "*PaymentService*"

Ejemplo 4 (Genérico): Generador de changelog

Genera el changelog entre dos tags de Git con el formato del equipo, listo para copiar al CHANGELOG.md o a la descripción del release.

# .claude/commands/git/changelog.md
---
description: Genera changelog entre dos tags de Git
argument-hint: [tag-anterior] [tag-nuevo]
allowed-tools: Bash
model: haiku
---
 
!git log $1..$2 --pretty="%s (%h)" --no-merges
 
Genera un changelog estructurado basado en los commits anteriores.
 
Formato de salida:
## [versión] — fecha
 
### ✨ Nuevas funcionalidades
- descripción de cada feat commit
 
### 🐛 Correcciones
- descripción de cada fix commit
 
### ♻️ Refactorizaciones
- descripción de cada refactor commit (si son significativas)
 
### 🔧 Cambios internos
- resto de commits (chore, ci, docs, test)
 
Reglas:
- Convierte los mensajes técnicos a lenguaje comprensible para el equipo
- Agrupa commits del mismo módulo
- Omite commits triviales (bump version, fix typo)
- Breaking changes van al principio con ⚠️
/git:changelog v1.3.0 v1.4.0

Ejemplo 5 (Genérico): Explicación de código para documentación

Explica un archivo o clase en lenguaje natural y genera el Javadoc correspondiente. Útil para documentar código heredado o revisar documentación existente.

# .claude/commands/doc/explain.md
---
description: Explica código y genera Javadoc para clases o métodos
argument-hint: ruta/al/Archivo.java [método opcional]
allowed-tools: Read, Write
---
 
Lee y analiza: $1
 
Si se especificó un método ($2), enfócate en él.
Si no, analiza la clase completa.
 
Genera dos secciones:
 
## 1. Explicación en lenguaje natural
- Qué hace esta clase/método y por qué existe
- Cuáles son sus responsabilidades principales
- Con qué otras clases se relaciona (dependencias y dependientes)
- Casos de uso típicos
- Posibles problemas o limitaciones
 
## 2. Javadoc generado
Javadoc completo listo para añadir al código:
- @param para cada parámetro con descripción útil
- @return describiendo el valor de retorno
- @throws para cada excepción con la condición que la dispara
- Ejemplo de uso si el método no es trivial
 
Pregunta si quieres que aplique el Javadoc directamente al archivo.
# Documentar una clase completa:
/doc:explain src/main/java/com/miapp/pagos/PaymentService.java
 
# Documentar un método específico:
/doc:explain src/main/java/com/miapp/pagos/PaymentService.java charge

El repositorio que acompaña esta serie incluye todos los comandos descritos en este artículo, organizados por namespace. Están disponibles en GitHub.

ComandoModeloDescripciónTipo
/git:commitHaikuGenera y ejecuta un commit con Conventional Commits a partir del staged areaGenérico
/git:branchHaikuCrea una rama con el formato estándar del equipo a partir de una descripciónGenérico
/git:changelogHaikuGenera changelog entre dos tags con secciones por tipo de commitGenérico
/gen:serviceSonnetScaffolding completo de servicio Spring Boot: interfaz, implementación y testJava
/gen:controllerSonnetGenera un controller REST con endpoints CRUD completos y documentación OpenAPIJava
/gen:migrationSonnetGenera una migración Flyway con naming convention y rollback documentadoJava
/gen:featureSonnetScaffolding completo de un feature: entidad, repo, servicio, controller, testsJava
/fix:testsSonnetCorre los tests, analiza los fallos y los corrige distinguiendo bug vs. test obsoletoGenérico
/fix:buildSonnetCorre el build, captura los errores de compilación y los corrige en orden de dependenciaJava
/reviewOpusCode review del diff actual — modos: security | performance | architecture | allGenérico
/doc:explainSonnetExplica una clase o método y genera el Javadoc correspondienteGenérico
/doc:readmeSonnetGenera o actualiza el README de un módulo siguiendo la plantilla del equipoGenérico

Buenas prácticas

Empieza simple, itera

El mejor Custom Command no es el más completo sino el que realmente usas. Empieza con un comando de 5 líneas que resuelva tu problema más repetitivo, y añade complejidad solo cuando notes que le falta algo. Un comando de 50 líneas que nunca usas vale menos que uno de 10 que invocas 20 veces al día.

Usa el modelo correcto para cada tarea

No necesitas un modelo potente para corregir un punto y coma: añade model: haiku en el frontmatter y los comandos de tareas mecánicas se ejecutan casi al instante. Reserva Sonnet para implementación y Opus para análisis complejos.

Versiona los comandos en Git

Versionar .claude/commands/ en Git hace que todos los miembros del equipo tengan acceso a los mismos comandos sin configuración manual. Los comandos del proyecto son parte de la infraestructura del proyecto, igual que los scripts de build o los hooks de CI.

El ! es más eficiente que pedirle al agente que ejecute

Cuando sabes exactamente qué información necesitas al inicio del comando, usa ! para capturarla. El agente recibe el output como parte del contexto inicial y no necesita invocar herramientas para obtenerlo, lo que ahorra turnos y tokens.

Documenta con description y argument-hint

Aunque el frontmatter es opcional, description y argument-hint son los dos campos que más valor aportan por el costo que tienen (dos líneas). Sin ellos, en tres semanas ni tú recuerdas qué hace /gen:service.


Conclusión

Los Custom Commands son la capa de automatización más directa y controlable de Claude Code. A diferencia de los Hooks (que se disparan automáticamente) y las Skills (que el agente activa cuando las considera relevantes), los Commands ocurren exactamente cuando tú lo decides y exactamente como tú los definiste.

Los tres patrones que más impactan en la productividad diaria:

  • El trío de Git (/git:commit, /git:branch, /git:pr) elimina la fricción mental de recordar convenciones de naming y formato en cada operación de versión.
  • Los generadores con Tasks (/gen:feature, /gen:service) convierten una tarea de 30 minutos en una de 3, con la garantía de que el resultado sigue las convenciones del equipo.
  • El /review con modos hace que una revisión de código completa sea tan fácil como un /review all antes de abrir un PR.

Puedes encontrar todo el código de los commandos que creamos en el repositorio del tutorial en GitHub.

En el próximo artículo veremos MCP Servers: cómo conectar Claude Code a bases de datos, GitHub, Jira y otras herramientas externas para que el agente tenga acceso a información que va más allá del repositorio local.


© javatutoriales.com – Serie: Desarrollo Asistido por IA