Parte I de una serie sobre cómo monté un marketplace interno de plugins de Claude Code para mi equipo.

Es un patrón que se repite en cualquier equipo de desarrollo que empieza a usar Claude Code en serio: cada persona acaba construyendo, a su manera, su propia colección de convenciones, atajos y prompts guardados para que la IA entienda el stack del equipo. El problema de siempre: ese conocimiento vive en el portátil de cada uno. Si alguien se va de vacaciones, se incorpora al equipo o simplemente cambia de proyecto, todo ese contexto se pierde.

A mí me tocó resolver justo eso, y hice lo que suele funcionar en estos casos: convertirlo en un producto interno, aunque sea pequeño. Monté un repositorio que es, a la vez, un laboratorio de experimentos y un marketplace de plugins de Claude Code. Con un solo comando, cualquiera del equipo instala de golpe todas las convenciones, skills y automatizaciones que se han ido decantando.

Lo interesante no es la idea (instalar cosas desde un catálogo no es nueva). Lo interesante es que, al construirlo, me obligó a entender todos los tipos de piezas que puede llevar un plugin (y creo que vale la pena compartirlo porque casi nadie usa más de una o dos).

Aquí va el mapa completo, con ejemplos reales (anonimizados) de lo que hemos montado.

1. Skills propias

Una skill es, en esencia, un documento de instrucciones que Claude carga solo cuando hace falta (no ocupa contexto todo el rato, aparece cuando la tarea coincide con su descripción).

Las primeras que suelen escribirse son las más aburridas y las más rentables: convenciones del equipo. Cómo se nombran las ramas, el formato de los mensajes de commit, qué se espera ver en una pull request. Y una segunda capa, más técnica, con los patrones arquitectónicos del stack que use el equipo: cómo estructurar un endpoint, cómo manejar errores, qué capas no se deben saltar.

Nada de esto es glamuroso. Pero significa que deja de repetirse la misma corrección en cada revisión de código (la convención está escrita una vez y Claude la aplica sola cuando alguien toca ese tipo de archivo).

2. Skills de terceros, apuntando a otros repos

Esta es la pieza que menos gente conoce y la que más me sorprendió al descubrir que existía: un plugin no tiene que contener el código de la skill. Puede limitarse a apuntar a un repositorio de otra persona.

Un caso típico: el frontend de un proyecto usa un framework bastante estándar del ecosistema, y ya existe un repositorio público de código abierto que mantiene skills sobre ese framework. En lugar de copiar y mantener una versión propia, se puede referenciar directamente ese repositorio, con una técnica que descarga solo la carpeta necesaria (no el repo entero) y opcionalmente fija una versión concreta para que una actualización de otra persona no rompa nada sin que nadie se entere.

Ventaja real: cuando quien mantiene el repositorio original mejora esas skills, el equipo las recibe sin que nadie tenga que tocar nada. Y si algo se rompe, basta con tener anotado el commit exacto al que volver.

3. Servidor MCP propio

MCP es el protocolo que permite que Claude hable con sistemas externos (bases de datos, APIs internas, lo que sea) a través de herramientas bien definidas, no solo texto libre.

Cuando el sistema con el que quieres conectar es interno y no existe una integración de terceros, la opción es escribir tu propio servidor MCP. Vive dentro del propio plugin (no en un directorio aparte del repositorio, porque solo lo que está dentro del plugin se copia al instalar) y se referencia con una variable de entorno especial para que las rutas funcionen sin importar dónde se instale.

Lo bueno de emparejarlo con una skill en el mismo plugin: en una sola instalación, el equipo recibe la skill y la herramienta que necesita para ejecutarla. Nadie tiene que configurar nada por separado.

4. Servidor MCP de terceros

Aquí la diferencia es que no hay nada que programar (solo configuración). Si un proveedor (por ejemplo, tu gestor de incidencias o tu wiki corporativa) ya ofrece un servidor MCP, tu plugin solo necesita declarar cómo arrancarlo: el comando, los argumentos, qué variables de entorno espera.

El plugin se convierte en un simple envoltorio de distribución: en vez de que cada persona busque el paquete adecuado y lo configure a mano, el equipo entero recibe la conexión ya lista al instalar. Eso sí (nunca credenciales en el repositorio, solo la receta para conectarse).

5. Hooks

Los hooks son comandos que el propio Claude Code ejecuta automáticamente en ciertos eventos (antes de una llamada a herramienta, después de que Claude termine, etc.), no algo que Claude “decide” hacer. Son el sitio correcto para reglas que tienen que cumplirse siempre, no solo cuando a la IA le parece buena idea (por ejemplo, bloquear un comando destructivo o forzar un formateo de código antes de aceptar un cambio).

La distinción importa más de lo que parece: una skill es una sugerencia que Claude puede seguir o no según el contexto; un hook es una barrera que se ejecuta sí o sí. Si algo debe pasar siempre, va en un hook, no en una skill.

6. Agentes (subagents)

Además de skills, un plugin puede incluir definiciones de subagentes: perfiles especializados con su propio conjunto de herramientas y su propio criterio, pensados para tareas concretas (revisar código, explorar un repositorio grande, redactar un plan). Se invocan desde la conversación principal y devuelven un resultado, sin cargar todo ese contexto especializado en la conversación de todos los días.

7. El propio catálogo (el “marketplace”)

Y por encima de todo esto hay un fichero de catálogo: la lista de qué plugins existen, de dónde se instalan y qué versión tienen. Es la pieza que convierte “una carpeta de scripts en mi repo” en algo que el resto del equipo puede descubrir e instalar con dos comandos, sin tener que preguntarte a ti directamente cómo iban las cosas.

Por dentro: cómo se ve esto en código

Para quien quiera algo más concreto que la teoría, así es la estructura real de un plugin de este marketplace:

plugins/mi-plugin/
├── .claude-plugin/plugin.json   # manifiesto: nombre, versión, dependencias
├── skills/<nombre>/SKILL.md     # skills propias → /mi-plugin:<nombre>
├── agents/<nombre>.md           # subagentes especializados
├── hooks/hooks.json             # hooks del ciclo de vida
└── .mcp.json                    # servidores MCP que trae el plugin

Todo eso cuelga directamente de la raíz del plugin (nada dentro de .claude-plugin/ salvo el propio manifiesto). La razón práctica: al instalar, Claude Code copia el directorio del plugin entero a una caché local, así que cualquier ruta que apunte fuera de esa carpeta simplemente no existe en la máquina de otra persona. Por eso las rutas internas se referencian con una variable como ${CLAUDE_PLUGIN_ROOT} en vez de rutas relativas al repo.

El catálogo (marketplace.json) es el que decide si una entrada es “nuestra” o “de terceros”. Una entrada propia es así de simple:

{
  "name": "team-dx",
  "source": "./plugins/team-dx",
  "version": "0.3.0"
}

Una entrada que referencia el repositorio público de otro equipo, sin copiar nada, es distinta: en vez de source como ruta, es un objeto que describe de dónde traer solo una carpeta:

{
  "name": "team-dx-frontend",
  "source": {
    "source": "git-subdir",
    "url": "https://github.com/alguien/skills.git",
    "path": "skills",
    "ref": "main"
  },
  "skills": ["./vue", "./pinia", "./vitest"]
}

ref: main significa que seguimos la rama, sin fijar una versión (recibimos las mejoras de quien mantiene ese repo sin revisarlas antes). Es una decisión consciente, no un descuido: a cambio, guardamos en metadata (un campo que Claude Code ignora, pero que nosotros sí leemos) el último commit conocido bueno, por si una actualización rompe algo y hay que congelar esa referencia con un sha exacto en vez de ref.

Para el MCP propio, la única diferencia respecto a un servidor normal es dónde vive y cómo se referencia:

{
  "mcpServers": {
    "mi-servidor": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/servers/mi-servidor/index.js"]
    }
  }
}

Para el MCP de terceros, el mismo fichero, pero sin nada propio que ejecutar (solo el comando que el proveedor documenta):

{
  "mcpServers": {
    "gestor-incidencias": {
      "command": "npx",
      "args": ["@proveedor/mcp-server"]
    }
  }
}

Y algo que no es obvio hasta que lo pisas: las herramientas que expone un servidor MCP de un plugin quedan con un nombre con espacio de nombres (mcp__plugin_<nombre-del-plugin>__<servidor>__<herramienta>) y si vas a escribir un hook que reaccione solo a esa herramienta, el matcher tiene que usar ese nombre completo. Poner el nombre “corto” del servidor en el hook simplemente no dispara nunca.

Por último, la regla que más disciplina exige y menos se ve: la versión es lo que decide si alguien recibe el cambio. Si tocas una skill y no subes el número en plugin.json y en marketplace.json (los dos, tienen que coincidir), el cambio queda escrito en el repo pero nadie que ya tenga el plugin instalado lo va a recibir. Hay un comando (claude plugin tag <ruta> --dry-run) que solo comprueba que ambos números coincidan (no que hayas subido el que corresponde), esa parte sigue siendo criterio humano: ¿rompe algo existente (MAJOR), añade capacidad (MINOR), o solo pule lo que ya había (PATCH)?

Lo que me llevo

Ninguna de estas piezas es complicada por separado. Lo que cambia las cosas es tratarlas como lo que son: artefactos de infraestructura de equipo, con versión, con quién es dueño de qué, y con la disciplina de que un cambio sin versión nuevo es un cambio que nadie recibe. Es exactamente el mismo cuidado que le pondríamos a una librería interna (porque, en la práctica, es exactamente eso).

Si tu equipo ya tiene tres personas escribiendo cada una su propia versión de “cómo le explico a la IA nuestras convenciones”, probablemente ha llegado el momento de convertir eso en un plugin.


¿Vosotros habéis montado algo similar? Me interesa mucho comparar notas sobre cómo estáis versionando y distribuyendo este tipo de configuración en equipo.