Saltar al contenido
Curso Claude Code en equipo: una sola forma de trabajar
06/29 El plugin y el marketplace en local Hooks en un plugin de Claude Code: comprobar el repo al abrir la sesión con SessionStart
Tu lectura Quedan 18 min
Lección 6 de 29 · El plugin y el marketplace en local

Hooks en un plugin de Claude Code: comprobar el repo al abrir la sesión con SessionStart

18 min de lectura Claude Code 2.1

Hola, bienvenido. En esta lección vamos a añadir al plugin team su primer hook. Se ejecuta al abrir cada sesión de Claude Code y comprueba que el repo cumple el contrato del equipo: los scripts de Composer, las líneas que tienen que estar en .gitignore y la versión del plugin que el repo pide. Si falta algo, lo dice y ofrece el comando para arreglarlo. Si todo está en orden, no muestra nada. Así, lo que el equipo ha acordado se comprueba solo, sin que nadie tenga que acordarse.

El contrato que fijamos al preparar el proyecto solo sirve si todos los repos lo cumplen, y nadie va a revisarlo a mano cada mañana. En el equipo de Marta, cuando a un repo le faltaba algo, se descubría tarde: un composer pint:test que no existía, un settings.local.json que alguien había subido sin querer o un compañero con una versión vieja de la configuración. Un hook SessionStart lo detecta en el momento en que alguien abre Claude en ese repo, antes de que el problema afecte al trabajo de nadie.

Qué es un hook y qué eventos tiene lo tienes en la lección Qué son los hooks de Claude Code y cuándo usarlos (se abre en una pestaña nueva) del curso de Claude Code. Lo que cambia aquí es que el hook va en el plugin y no en el repo, y eso tiene sus reglas. Además de Claude Code, necesitas jq, que es lo que usan los scripts del plugin para leer JSON.

Compruébalo con jq --version. Si no lo tienes, en Ubuntu, Debian o WSL2 se instala así, desde cualquier pestaña:

Terminal
sudo apt-get install jq

Y en macOS, con Homebrew:

Terminal
brew install jq

Los hooks de un plugin van en hooks/hooks.json

En un repo, los hooks se declaran en .claude/settings.json. En un plugin van en hooks/hooks.json, en la raíz del plugin, con una clave hooks que tiene la misma forma que la de los settings. Cuando el plugin está activo, Claude Code junta sus hooks con los del usuario y los del proyecto. Vamos a crear las carpetas que necesitamos en esta lección, en la pestaña claude-plugins:

Terminal
mkdir -p plugins/team/hooks plugins/team/scripts plugins/team/skills/doctor plugins/team/tests/fixtures

Y el archivo de hooks, claude-plugins/plugins/team/hooks/hooks.json:

claude-plugins/plugins/team/hooks/hooks.json Nuevo +16
1{
2 "description": "Comprueba al abrir cada sesión que el repo cumple el contrato del equipo",
3 "hooks": {
4 "SessionStart": [
5 {
6 "matcher": "startup",
7 "hooks": [
8 {
9 "type": "command",
10 "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/doctor.sh"
11 }
12 ]
13 }
14 ]
15 }
16}

SessionStart se ejecuta al arrancar una sesión nueva, pero también al retomar una con --resume, después de /clear y después de compactar. El matcher startup lo deja solo en las sesiones nuevas, que es cuando tiene sentido revisar el repo.

${CLAUDE_PLUGIN_ROOT} es la ruta en la que está instalado el plugin, y es versionada: cada versión instalada tiene su carpeta, así que la ruta cambia cuando el plugin se actualiza. Para lo que tenga que sobrevivir a una actualización existe ${CLAUDE_PLUGIN_DATA}, una carpeta que comparten todas las versiones del plugin y todos los repos de la máquina. En este curso no la vamos a necesitar.

Fíjate en las comillas alrededor de ${CLAUDE_PLUGIN_ROOT}. Si la ruta tuviera un espacio, sin comillas el comando se partiría en 2 y el hook no se ejecutaría. claude plugin validate lo sabe, y sin las comillas esto es lo que responde en modo estricto:

Salida
Validating plugin manifest: /home/marta/code/team/claude-plugins/plugins/team/.claude-plugin/plugin.json Validating hooks: /home/marta/code/team/claude-plugins/plugins/team/hooks/hooks.json ⚠ Found 1 warning: ❯ hooks.SessionStart: Shell command uses ${CLAUDE_PLUGIN_ROOT} without quotes: ${CLAUDE_PLUGIN_ROOT}/scripts/doctor.sh. If the expanded path contains a space the command can split into several words and fail. Wrap the placeholder in double quotes, or use exec form: {"command": "<executable>", "args": ["${CLAUDE_PLUGIN_ROOT}/..."]}. ✘ Validation failed (--strict treats warnings as errors)

El mensaje propone también la otra forma, con args, que ejecuta el script sin pasar por la shell. Las 2 funcionan. Nosotros nos quedamos con las comillas, que se leen de un vistazo.

Lo que queda de esta lección
  1. 02Qué comprueba el script doctor.sh
  2. 03systemMessage para la persona y additionalContext para el modelo
  3. 04La misma comprobación como skill: /team:doctor
  4. 05Probar el script sin abrir Claude: tests/run.sh y sus fixtures
  5. 06El env del repo y la prueba en una sesión
Sigue leyendo con tu suscripción El curso completo, con su proyecto final, el certificado y el foro, está incluido en la suscripción. Ver los planes