Cap 15: Plugins

Por: Artiko
claude-codepluginsmarketplacesdistribution

Qué son los Plugins

Los plugins extienden Claude Code con funcionalidad custom compartible entre proyectos y equipos. Pueden incluir skills, agents, hooks, MCP servers, LSP servers, monitors, settings y binarios.

Plugins vs configuración standalone

ApproachSkill namesBest para
Standalone (.claude/)/helloWorkflows personales, customización por proyecto, experimentos
Plugins (con .claude-plugin/plugin.json)/plugin-name:helloCompartir con el equipo, distribuir a la comunidad, versionado, reusable

Usa standalone cuando customizás para un único proyecto y los nombres cortos importan.

Usa plugin cuando quieres compartir, versionar, distribuir via marketplace, o reusar en múltiples proyectos. Los plugin skills tienen namespace para evitar conflictos.

Empezá con standalone para iterar rápido y convertí a plugin cuando estés listo para compartir.

Por qué skills/ y no commands/

Los comandos personalizados y las skills se fusionaron en un mismo sistema: .claude/commands/deploy.md y .claude/skills/deploy/SKILL.md generan ambos /deploy y comparten el mismo frontmatter. Ante colisión de nombre, gana la skill. Esa es la razón de fondo por la que en plugins nuevos conviene escribir todo como skills. Ver Extend Claude with skills.

Quickstart

1. Crear directorio del plugin

mkdir my-first-plugin
mkdir my-first-plugin/.claude-plugin

2. Crear el manifest

my-first-plugin/.claude-plugin/plugin.json:

{
  "name": "my-first-plugin",
  "description": "A greeting plugin to learn the basics",
  "version": "1.0.0",
  "author": { "name": "Your Name" }
}
CampoPropósito
nameIdentificador único y namespace de skills. Los skills llevan prefix (/my-first-plugin:hello)
descriptionMostrado en el plugin manager
versionOpcional. Si se setea, los users reciben updates solo cuando bumpés. Sin esto, el commit SHA se usa como versión
authorOpcional. Atribución

El manifiesto es opcional: si falta, los componentes se autodescubren y el nombre sale del directorio. Si existe, solo name es obligatorio.

Campos soportados por el schema vigente:

$schema, displayName (v2.1.143+), version, description, author, homepage, repository, license, keywords, defaultEnabled (v2.1.154+), skills, commands, agents, hooks, mcpServers, outputStyles, lspServers, userConfig, channels, dependencies y experimental.{themes,monitors}.

Los campos no reconocidos se ignoran con un warning; claude plugin validate --strict los convierte en error. Ver Plugin manifest schema.

Plugin de una sola skill (v2.1.142+): un plugin con SKILL.md en la raíz se carga directamente como plugin de una skill, sin necesidad del directorio skills/ ni del manifiesto.

3. Agregar un skill

mkdir -p my-first-plugin/skills/hello

my-first-plugin/skills/hello/SKILL.md:

---
description: Greet the user with a friendly message
disable-model-invocation: true
---

Greet the user warmly and ask how you can help them today.

4. Testear el plugin

claude --plugin-dir ./my-first-plugin

Y luego /my-first-plugin:hello. Run /help para ver el skill bajo el plugin namespace.

Plugin skills están siempre namespaced para evitar conflictos. Para cambiar el prefix, actualizá name en plugin.json.

5. Argumentos en skills

---
description: Greet the user with a personalized message
---

# Hello Skill

Greet the user named "$ARGUMENTS" warmly and ask how you can help them today.

Run /reload-plugins para recargar, luego /my-first-plugin:hello Alex.

Estructura de un plugin

Error común: NO pongas commands/, agents/, skills/, ni hooks/ dentro de .claude-plugin/. Solo plugin.json va ahí. Las demás carpetas van en el plugin root.

DirectorioLocationPropósito
.claude-plugin/Plugin rootContiene plugin.json (opcional si componentes usan locations default)
skills/Plugin rootSkills como <name>/SKILL.md directorios
commands/Plugin rootCommands como archivos Markdown planos. Usa skills/ para plugins nuevos
agents/Plugin rootAgent definitions. Los subagentes de plugin ignoran por seguridad hooks, mcpServers y permissionMode
hooks/Plugin rootEvent handlers en hooks.json
.mcp.jsonPlugin rootMCP server configs
.lsp.jsonPlugin rootLSP server configs para code intelligence
output-styles/Plugin rootOutput styles del plugin (campo outputStyles del manifiesto)
bin/Plugin rootEjecutables agregados al PATH del Bash tool mientras el plugin esté enabled
settings.jsonPlugin rootDefault settings aplicados cuando el plugin está enabled

Monitors y themes ya no se declaran al nivel superior: viven bajo experimental.{themes,monitors} en el manifiesto (ver Background monitors).

Identidad de subagentes en plugins: a diferencia de los subagentes normales (donde la identidad viene solo del campo name), en plugins el path cuenta: agents/review/security.md se registra como my-plugin:review:security.

Reglas de resolución de rutas

Todas las rutas del manifiesto son relativas a la raíz del plugin y empiezan por ./. Lo que hacen respecto del directorio por defecto:

CampoComportamiento
commands, agents, outputStyles, experimental.themes, experimental.monitorsReemplazan el directorio por defecto
skillsSe suma al escaneo por defecto de skills/
hooks, mcpServers, lspServersTienen reglas de fusión propias

Variables disponibles en las rutas y comandos:

VariableSignificado
${CLAUDE_PLUGIN_ROOT}Raíz del plugin instalado
${CLAUDE_PLUGIN_DATA}Directorio persistente del plugin, sobrevive a las actualizaciones
${CLAUDE_PROJECT_DIR}Raíz del proyecto donde corre la sesión

Ver Path behavior rules.

Componentes avanzados

Skills

flowchart TD
    A["my-plugin/"] --> B[".claude-plugin/"]
    B --> C["plugin.json"]
    A --> D["skills/"]
    D --> E["code-review/"]
    E --> F["SKILL.md"]

Después de instalar el plugin, /reload-plugins para cargar. Ver Skills para frontmatter completo.

LSP servers

Plugins LSP dan a Claude code intelligence en tiempo real. Para lenguajes comunes (TS, Python, Rust) usa los plugins oficiales. Para custom:

.lsp.json:

{
  "go": {
    "command": "gopls",
    "args": ["serve"],
    "extensionToLanguage": {
      ".go": "go"
    }
  }
}

Los users instalando deben tener el binario instalado en su máquina.

Background monitors

Observan logs, files, o status externo y notifican a Claude.

Monitors y themes son campos experimentales del manifiesto: se declaran bajo experimental en plugin.json, y la ruta que indiques reemplaza el directorio por defecto.

{
  "name": "my-plugin",
  "experimental": {
    "monitors": "./monitors/monitors.json",
    "themes": "./themes"
  }
}

Contenido del archivo de monitors:

[
  {
    "name": "error-log",
    "command": "tail -F ./logs/error.log",
    "description": "Application error log"
  }
]

Cada stdout line del command se entrega a Claude como notificación durante la sesión.

Output styles

Los plugins pueden traer output styles vía el campo outputStyles del manifiesto (reemplaza el directorio por defecto). Frontmatter disponible: name, description, keep-coding-instructions (default false) y force-for-plugin (solo plugins, default false), que fuerza el estilo mientras el plugin esté habilitado.

/output-style fue deprecado en v2.1.73 y eliminado en v2.1.91: hoy el estilo se cambia con /config o con el campo outputStyle en settings. Ver Output styles.

Default settings con settings.json

Plugins pueden incluir settings.json en el root con defaults aplicados al habilitarse. Actualmente solo agent y subagentStatusLine están soportados.

{
  "agent": "security-reviewer"
}

Esto activa el agente security-reviewer definido en agents/ como main thread cuando el plugin se habilita.

MCP servers

.mcp.json en el plugin root. Los inline servers se conectan al startup del plugin y se desconectan al deshabilitarlo.

Naming de las herramientas de plugin (difiere del estándar mcp__<server>__<tool>):

ElementoForma
Herramientamcp__plugin_<plugin>_<server>__<tool>
Registro del servidorplugin:<plugin>:<server>

Consecuencia práctica: un matcher de hook escrito contra la clave desnuda (mcp__database-tools__.*) nunca dispara para un servidor provisto por un plugin. Ver MCP.

Testing local

# Directorio
claude --plugin-dir ./my-plugin

# ZIP archive (v2.1.128+)
claude --plugin-dir ./my-plugin.zip

# Múltiples plugins
claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two

# Desde URL
claude --plugin-url https://example.com/plugin.zip

Cuando un plugin con --plugin-dir tiene el mismo nombre que uno instalado del marketplace, la versión local tiene precedencia para esa sesión. Excepción: plugins force-enabled/disabled por managed settings no pueden ser overridden con --plugin-dir.

Claves managed-only que gobiernan plugins

Estas claves solo tienen efecto en los managed settings de la organización (no en user ni project):

ClaveEfecto
allowedChannelPluginsRestringe qué plugins pueden venir por channels
blockedMarketplacesLista de marketplaces bloqueados
strictKnownMarketplacesSolo permite marketplaces conocidos/declarados
strictPluginOnlyCustomizationBloquea skills, agents, hooks y MCP servers provenientes de fuentes de usuario y de proyecto
channelsEnabledHabilita o deshabilita el sistema de channels
disableSideloadFlagsDesactiva --plugin-dir / --plugin-url
pluginTrustMessageMensaje de confianza mostrado al instalar plugins
allowManagedHooksOnlyBloquea hooks de usuario, proyecto y plugin, salvo los de plugins force-enabled

Ver Permissions y Settings.

/reload-plugins recarga sin reiniciar (incluye skills, agents, hooks, MCP servers, LSP servers del plugin).

Debugging

  1. Valida el manifiesto:
claude plugin validate ./my-plugin
claude plugin validate ./my-plugin --strict

Por defecto los campos no reconocidos de plugin.json solo generan un warning; con --strict se convierten en error. Es la primera herramienta a usar cuando un plugin “carga pero no hace nada”.

  1. Verifica la estructura: directorios en el plugin root, no dentro de .claude-plugin/
  2. Test componentes individualmente: cada skill, agent, hook separado
  3. Ver Debugging tools para CLI commands

Distribución

Pasos para compartir:

  1. README.md con instrucciones de instalación y uso
  2. Versioning strategy: setear version explícito o usar commit SHA del git
  3. Marketplace: distribuir via plugin marketplaces o repositorio privado para uso interno
  4. Test con el equipo antes de publicar

Schema de .claude-plugin/marketplace.json

Un marketplace es un repositorio con .claude-plugin/marketplace.json en la raíz.

CampoObligatoriedad
nameObligatorio
ownerObligatorio
pluginsObligatorio (array)
$schema, description, versionOpcionales
metadata.pluginRootOpcional. Raíz desde la que resuelven las rutas relativas
allowCrossMarketplaceDependenciesOnOpcional. Marketplaces cuyos plugins pueden usarse como dependencias
renames (v2.1.193+)Opcional. Mapea nombres viejos a nuevos

Cada entrada de plugins requiere name y source. Tipos de source:

TipoForma
Ruta relativa"./plugins/mi-plugin"
GitHub{ "source": "github", "repo": "org/repo", "ref"?: "...", "sha"?: "..." }
URL{ "source": "url", "url": "...", "ref"?: "...", "sha"?: "..." }
Subdirectorio git{ "source": "git-subdir", "url": "...", "path": "...", "ref"?: "...", "sha"?: "..." }
npm{ "source": "npm", "package": "...", "version"?: "...", "registry"?: "..." }

Campos extra por plugin: category, tags, strict, relevance (v2.1.152+) y defaultEnabled (v2.1.154+).

{
  "name": "mi-marketplace",
  "owner": { "name": "Mi Equipo" },
  "plugins": [
    { "name": "code-review", "source": "./plugins/code-review", "category": "quality" },
    { "name": "deploy-tools", "source": { "source": "github", "repo": "mi-org/deploy-tools" } }
  ]
}

Nombres reservados: Anthropic reserva nombres de marketplace como claude-code-plugins, agent-skills, healthcare y first-party-plugins. Usar uno de ellos hace fallar la carga del marketplace. first-party-plugins y healthcare se reservaron en v2.1.205.

Ver Marketplace schema.

Submit al marketplace oficial

Antes de enviar, verifica que el nombre del marketplace no colisione con los nombres reservados listados arriba.

Convertir standalone a plugin

mkdir -p my-plugin/.claude-plugin

my-plugin/.claude-plugin/plugin.json:

{
  "name": "my-plugin",
  "description": "Migrated from standalone configuration",
  "version": "1.0.0"
}

Copiar configuraciones:

cp -r .claude/commands my-plugin/
cp -r .claude/agents my-plugin/
cp -r .claude/skills my-plugin/

Migrar hooks: crear my-plugin/hooks/hooks.json copiando el objeto hooks desde .claude/settings.json.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npm run lint:fix" }]
      }
    ]
  }
}

Testear:

claude --plugin-dir ./my-plugin

Después de migrar puedes borrar los archivos originales de .claude/ para evitar duplicados. La versión del plugin tendrá precedencia.

Diferencias estándar vs plugin

StandalonePlugin
Solo en un proyectoCompartible via marketplaces
Files en .claude/commands/Files en plugin-name/commands/
Hooks en settings.jsonHooks en hooks/hooks.json
Copiar manualmente para compartirInstall con /plugin install

Instalación de plugins existentes

/plugin install code-review@claude-plugins-official

Marketplace de equipo: configurar plugin marketplaces en repos privados para distribución interna.

CLI commands

claude plugin install <plugin>@<marketplace>
claude plugin list
claude plugin remove <plugin>

Alias: claude plugins. Ver plugin reference CLI commands.

Recomendar tu plugin desde tu CLI

Una vez listado en el marketplace, puedes tener tu propio CLI que prompts a usuarios de Claude Code a instalarlo. Ver /en/plugin-hints en la doc oficial.


Siguiente: Checkpointing y Sesiones