Plugins para agentes de IA: un bundle, todo tu equipo
13 conceptos, 80% del uso real · lectura conceptual de unos 90 minutos · un día enfocado para el primer plugin real · de una carpeta vacía a un plugin que un compañero instala con un comando
Primero: qué es realmente un plugin. De fábrica, un agente de código como Claude Code u OpenCode es un generalista capaz. Puede trabajar en cualquier proyecto, pero no conoce tu forma de trabajar. Un plugin es el paquete que corrige eso con una instalación: reúne los playbooks que sigue el agente (skills), los especialistas a los que delega (subagentes), los sistemas que puede alcanzar (servidores MCP), tus instrucciones permanentes y las reglas que no puede saltarse (hooks). Entrega ese bundle a un agente genérico y se vuelve tuyo; un compañero que lo instala recibe exactamente el mismo.
Ahora mira eso hecho realidad. Anthropic distribuye marketplaces completos de estos plugins. Dos comandos, claude plugin marketplace add anthropics/knowledge-work-plugins y luego claude plugin install finance@knowledge-work-plugins, y un Claude vacío se vuelve especialista financiero: skills que se activan solas, comandos como /finance:reconciliation y conectores a los sistemas donde vive un equipo de finanzas. Cambia finance por sales o legal y obtienes ese especialista. Eso es un plugin: una instalación convierte a un generalista en el experto exacto que necesitas. Al final de este curso habrás construido uno propio y habrás visto a dónde conduce: marketplaces de dominio vendibles como agentfactory-business (banking, legal-ops, Islamic finance), que ponen profundidad de dominio regulado encima de Anthropic.
Un bundle es específico del host; la mayoría de lo que contiene no. Un plugin de Claude Code y uno de OpenCode envuelven las mismas piezas en formatos distintos que no cargan entre sí (el Concepto 2 muestra por qué). Pero las piezas sí viajan en su mayoría: una skill es el mismo SKILL.md en todas partes, tus instrucciones son el mismo markdown y un servidor MCP es una URL a la que cualquier host puede apuntar. Solo el hook es realmente por-host, porque se conecta a una maquinaria distinta dentro de cada host (lo verás en el Concepto 7). Así construyes para el host que usas, y mucho de lo que va dentro aún llega a claude.ai, Codex, Cursor e incluso a un agente personal como OpenClaw.
Y esto es lo que vienes a aprender. Tu agente ya conoce la sintaxis; puede escribir un hook o un manifiesto cuando se lo pides. Si eso fuera todo lo que enseña un curso, el agente lo volvería inútil. Lo escaso es el juicio que no tiene: qué palanca necesita un trabajo, cuándo una regla debe ser una garantía y no una esperanza, y cómo probar lo que afirmas sobre un plugin. Por eso diriges en inglés claro, construyes cada palanca desde una carpeta vacía, comparas contra una build completa y probada, y envías un plugin real que un compañero instala con un comando. Tú tomas las decisiones; el agente escribe.
Todo sigue de un hecho: extiendes un agente que no posees. El host posee el loop, el modelo y la máquina. Tu plugin no dirige el espectáculo; entrega piezas para que el host las cargue. De ahí salen cuatro reglas no negociables, y todo el curso construye esas cuatro:
- Bundle para compartir. Un plugin es la forma compartible y versionada de una personalización. Si solo es para ti en un repo, necesitas una carpeta
.claude/, no un plugin. Usa un plugin cuando otros también deban recibirlo. - La palanca correcta para el trabajo. Una skill es conocimiento que el agente usa por elección; un subagente es trabajo que delega; un servidor MCP son herramientas y datos que alcanza; un hook es código que corre por sí solo en momentos fijos. Haz coincidir el trabajo con la palanca.
- Lo obligatorio es un hook, no una instrucción. Cualquier cosa en una skill o
CLAUDE.mdes consejo que el modelo puede saltarse. Un hook es código que se ejecuta siempre. Si tiene que ocurrir, como un formatter o una guarda de seguridad, es un hook. - Un plugin se ejecuta dentro de la confianza del usuario. Ejecuta código en la máquina de quien lo instala. Construye con privilegio mínimo, di qué toca y trata instalarlo o enviarlo como una decisión de confianza.

Lee cada Concepto preguntando: ¿qué invariante es este?
Prerequisitos. Esta página asume tres cosas.
- Diriges un agente de código. Ya hiciste el Agentic Coding Crash Course: Claude Code u OpenCode, modo plan, archivo de reglas. Construimos a través de ese banco de trabajo.
- Puedes leer código tipado: shell, un poco de JSON y TypeScript, directamente o pegando bloques a tu agente para que los explique en lenguaje claro.
- Recomendado: Connector-Native Apps. Ese curso enseñó el mismo hábito, saber en qué capa estás, y construyó un servidor MCP. Un plugin puede apuntar a uno (Concepto 6), así que los dos se conectan.
No necesitas Build AI Agents ni AI Identity primero. Ambos vienen después en la ruta, y este curso apunta hacia ellos.
Dónde encaja. En Mode 2, justo después de Connector-Native Apps. La ruta es: Connector-Native Apps → este curso → AI Identity (sign-in & agent access) → Build AI Agents. Las apps connector-native extienden la app de chat para usuarios finales; los plugins extienden el agente de código para constructores. El mismo movimiento, el otro host.
Preparación (unos minutos)
Aquí no ejecutarás comandos de shell a mano. Diriges tu agente de código en inglés claro y revisas lo que reporta, el mismo loop que usarás para construir el plugin. La preparación es tu primera repetición.
-
Descarga la base (
plugins-crash-course-base.zip), descomprímela y abre la carpetaplugins-crash-courseen Claude Code (o OpenCode). Al abrirla, el agente leeAGENTS.md: el brief de lo que estás construyendo y dónde vive la referencia probada. -
Dile que se prepare. Pega:
Set up my base environment, then tell me what you did and what passed.
Detrás de esa línea, tu agente sigue el brief de AGENTS.md: en Claude Code instala la skill oficial de estructura de plugins para trabajar desde la spec actual; en OpenCode lee la documentación de plugins; luego ejecuta los checks de la build de referencia.
- Ahora haz que te enseñe el layout. Pega:
Walk me through, in plain English, how a plugin is laid out on my host.
Hecho cuando tu agente informa que la referencia está verde (su guarda bloquea .env y rm -rf, la skill de muestra y el servidor MCP pasan) y puede explicarte el layout de plugins de tu host.
Qué hay en la caja. Casi nada tuyo todavía, y ese es el punto. Tú construyes el plugin; el starter te da un brief y una build probada contra la cual revisar tu trabajo.
plugins-crash-course/ ← you build YOUR marketplace + plugin here, from blank
AGENTS.md your brief + how each host lays out a plugin
CLAUDE.md points Claude Code at the same brief (@AGENTS.md)
reference/ a COMPLETE, PROVEN build — read it, diff against it, don't copy it
plugins/agent-factory/ the finished plugin: proven guard, a model skill, a model reviewer
server/ a runnable MCP server you point your plugin at
verify.sh one command that proves the reference is sound
Construirás cada palanca tú mismo: el hook de guarda, una skill para un trabajo que de verdad tienes, un subagente reviewer, el cableado MCP, el marketplace. Diriges a tu agente en inglés claro. Cuando una pieza vuelva mal, la comparas con reference/, la versión conocida y correcta. Tú diriges; el agente escribe; tú revisas; tú comparas.
Mira uno funcionar antes de construir uno (5 minutos)
Acabas de leer qué hace un plugin. Ahora siéntelo. Antes de los conceptos, instala el plugin terminado que viene en el starter y mira cómo impone algo. Verlo primero hace que el resto encaje.
Carga el plugin de referencia en una sesión:
claude --plugin-dir reference/plugins/agent-factory
Abre reference/plugins/agent-factory en OpenCode. Carga la guarda desde .opencode/plugins/ de esa carpeta y la skill desde skills/.
Luego ponlo a trabajar. Pega:
Try to read a file called
.env, then use your loop-engineering skill to explain an agent loop in four moves.
Lo que deberías ver:
- El agente queda bloqueado al leer
.env, y te dice por qué. (un hook que se dispara en una llamada de herramienta que el modelo no puede saltarse) - La skill responde con su propia voz, traída sin que la nombres. (una skill que eligió el modelo)
- (Claude Code) Pídele que arregle un archivo desordenado y vuelve autoformateado, sin pedirlo. (un segundo hook)
Ese bloqueo duro sobre .env es lo que una instrucción tipo "por favor no leas secretos" nunca puede garantizar, y aprender a construirlo es el corazón de este curso. No configuraste nada por archivo; el plugin trajo el comportamiento consigo. Ahora los conceptos tienen algo real a lo que pegarse.
Parte 1: la forma
Concepto 1: extiendes el agente, no lo posees
Un plugin no es un programa que ejecutas. Es un conjunto de piezas que un host carga y ejecuta por ti. El host, Claude Code u OpenCode, posee el bucle del agente (el ciclo decidir-actuar-repetir), trae el modelo y se ejecuta en el equipo del usuario. Tu plugin aporta capacidades y reglas que el host recoge. Si esa imagen está clara, el resto son detalles; si está equivocada, intentarás hacer que el plugin "haga" cosas que nunca estuvieron a su cargo.
Aquí hay un giro elegante que conviene nombrar: diriges un agente de código para construir un plugin para agentes de código. Le dirás a Claude Code que escriba el mismo tipo de extensión que Claude Code carga. La herramienta que lo construye y la herramienta que extiende son de la misma familia. No es un truco: es la forma más rápida de construir uno, y así funciona cada curso de Manufacturing. Tú diriges, el agente escribe y tú verificas.
Concepto 2: dos hosts, una idea
Este curso cubre dos hosts. Empaquetan las extensiones de forma distinta, pero la idea es la misma: una unidad que el host carga.
- Claude Code recibe un paquete declarativo: una carpeta de componentes (skills, subagentes, hooks, servidores MCP) descrita por un manifiesto pequeño. Escribes principalmente configuración y scripts; Claude Code los conecta.
- OpenCode recibe un módulo de código: un archivo JavaScript/TypeScript que se engancha a los eventos del agente y puede añadir herramientas. Escribes funciones; OpenCode las llama.
| Plugin de Claude Code | Plugin de OpenCode | |
|---|---|---|
| Forma | una carpeta + manifiesto plugin.json | un módulo .ts/.js que exporta funciones |
| Escribes | skills, subagentes, config de hooks, .mcp.json | handlers de eventos, herramientas personalizadas |
| Se carga desde | un marketplace, o --plugin-dir | .opencode/plugins/ o un paquete npm |
No extienden mejor o peor: extienden de forma distinta, y vale la pena conocer la diferencia antes de elegir un objetivo. Claude Code es la herramienta de Anthropic, ligada a modelos Claude, con formato de paquete declarativo y un ecosistema de marketplace para distribuir. OpenCode es open source y agnóstico al modelo: trae tu propia API key, usa modelos gratuitos o locales (Gemini, GPT, local), y sus plugins son código, lo que da control más fino a costa de escribir más por tu cuenta. Para estudiantes sensibles al costo, esa libertad de modelo es el punto clave: la misma skill que escribes puede ejecutarse sobre un modelo gratuito en OpenCode. (Ambas herramientas también interoperan: las skills cruzan directamente, y plugins de comunidad conectan credenciales y backends entre ellas, pero eso es usar las herramientas juntas, no crear plugins, así que queda fuera de este alcance.)
La mayor parte del curso es el modelo mental compartido y la forma de Claude Code (es el paquete más rico); la Parte 5 muestra la forma de OpenCode para el mismo trabajo. Elige el host que realmente usas; los cuatro invariantes no cambian.
Una palanca se porta gratis; otra no. Una skill es solo un archivo SKILL.md, y los tres agentes de código de este curso leen ese formato de forma nativa: Claude Code, OpenCode y Codex. OpenCode descubre skills por su cuenta desde .opencode/skills/, .claude/skills/ y .agents/skills/ (no hace falta plugin para las skills). Así que una sola carpeta de skill puede servir a todas las herramientas. Los hooks son lo contrario: los hooks de Claude Code son configuración JSON, los de OpenCode son un módulo JavaScript; no hay formato compartido, así que escribes el hook una vez por host. Mantén esa separación en la cabeza; define cómo organizas un plugin entre herramientas (Concepto 4).
Esa separación escala a dos familias. El plugin de Claude Code que construyes también carga en Claude Cowork y claude.ai: comparten el formato de plugin de Anthropic. El plugin de OpenCode que construyes también carga en OpenWork, un agente de escritorio basado en OpenCode: el mismo formato de OpenCode. Las skills cruzan ambas familias (todo lee SKILL.md); los paquetes no cruzan (un paquete de Claude no es un módulo de OpenCode). Por tanto, el host que eliges determina hasta dónde viaja el paquete, pero una skill simple viaja a todas partes. Aquí nos quedamos en los dos agentes de código; los hosts de knowledge work tienen su propio curso (mira el techo).

Concepto 3: empaqueta para compartir, no configures para quedarte
Ambos hosts te permiten personalizar sin un plugin: Claude Code lee una carpeta .claude/ en tu proyecto; OpenCode lee .opencode/. Esa es la herramienta correcta cuando la personalización es personal y vive en un solo repositorio. Un plugin es lo que eliges cuando la personalización debe viajar: a tus compañeros, entre tus proyectos, a la comunidad, con versiones y actualizaciones.
Así que la prueba para saber si algo debe ser un plugin no es qué hace, sino quién más lo necesita. Un desarrollador, un proyecto: una carpeta .claude/. Un equipo, muchos proyectos o personas desconocidas: un plugin (invariante 1).
Una consecuencia temprana: las skills y los comandos de plugin tienen namespace por el nombre del plugin. Una skill hello en un plugin llamado repo-tools se invoca como /repo-tools:hello. Eso evita que dos plugins instalados choquen por el mismo nombre.
✓ Checkpoint: la forma está clara. Sabes que un plugin es una unidad cargada por un host, que dos hosts la empaquetan de forma distinta y que "plugin" significa "personalización hecha para compartir". Ahora, las cuatro palancas.
Parte 2: las palancas de capacidad
Tres de las cuatro palancas aumentan lo que el agente puede hacer. (La cuarta, los hooks, es lo bastante distinta para tener su propia parte.)

Concepto 4: skills, conocimiento que el agente usa por elección
Una skill es una carpeta con un archivo SKILL.md: una descripción más instrucciones. Claude lee la descripción y, cuando una tarea coincide, carga la skill por su cuenta: es invocada por el modelo. Una skill es la forma de enseñar al agente cómo hace tu equipo una cosa: tu checklist de revisión, tu formato de mensajes de commit, los pasos de tu proceso de release.
---
description: Review a diff for our team's standards. Use when reviewing code or a PR.
---
When reviewing, check in this order:
1. Does it match the existing patterns in the file?
2. Error handling and edge cases.
3. Tests for the new behavior.
4. Security: secrets, input validation, injection.
La descripción es la línea más importante: es lo que el modelo lee para decidir si la skill es relevante, así que escríbela sobre cuándo usar esto, no solo qué es. El cuerpo solo carga cuando la skill se activa, así que puede ser tan largo como necesite.
Como una skill es consejo que el modelo decide seguir, es la palanca correcta para guía, y la palanca equivocada para todo lo que debe ocurrir sin falta (eso es un hook, Concepto 8).
Escribe una skill una vez, y todas las herramientas la leen. Ese es el superpoder de una skill como palanca: el formato SKILL.md se comparte entre Claude Code, OpenCode y Codex. Para mantener una skill portable, mantén su cuerpo independiente de la herramienta: apóyate solo en los campos de frontmatter name y description, y no uses construcciones específicas como $ARGUMENTS, allowed-tools o disable-model-invocation. Entonces el mismo archivo funciona en todas partes: Claude Code lo carga desde skills/ dentro de tu plugin; OpenCode lo encuentra de forma nativa en .opencode/skills/ o .claude/skills/; Codex en .agents/skills/. El skills/loop-engineering/SKILL.md del starter es un ejemplo completo y portable: léelo.
¿Por qué solo frontmatter?
Cada host deriva el nombre de la skill y decide cuándo invocarla desde la description. Más allá de esos dos campos, los hosts divergen: lo que uno admite, otro lo ignora o se rompe con ello. Por eso, todo lo que pongas en el cuerpo y sea específico de una herramienta rompe silenciosamente la skill en las demás. Instrucciones simples en el cuerpo, dos campos en el frontmatter, y la skill es universal.
Concepto 5: subagentes, delegar con un contexto fresco
Un subagente es un ayudante al que el agente principal puede entregar un trabajo, con su propia ventana de contexto limpia y sus propias instrucciones. Lo defines como un archivo markdown en la carpeta agents/: frontmatter para su nombre y descripción; el cuerpo para su brief:
---
name: reviewer
description: Reviews a diff against our standards. Use after a change is written.
---
You review code in your own context. Check, in order: matches existing patterns,
error handling, tests, security. Report findings as a short ordered list.
Do not edit files — only review and report.
Delegar importa por dos razones: el subagente no se distrae con la conversación principal, y su trabajo no llena el contexto principal.
Recurre a un subagente cuando la tarea es autocontenida y verificable: "revisa este diff", "encuentra todos los lugares donde se llama a esta función", "escribe pruebas para este archivo". El agente principal se queda en la línea de avance; el subagente entra en profundidad y vuelve con un informe.
El error que debes evitar: convertir todo en subagente. Delegar tiene costo (hay que darle al contexto fresco lo que necesita). Úsalo cuando el foco y la hoja en blanco lo valgan, no para cada paso pequeño.
Concepto 6: servidores MCP, el alcance externo que puede enviar un plugin
La cuarta palanca le da al agente un alcance que antes no tenía: tu API interna, una base de datos, un servicio. Lo hace apuntando a un servidor MCP, y ya construiste uno en Connector-Native Apps. No construyes otro aquí. Todo el trabajo del plugin es cablearlo.
Un plugin se conecta mediante un archivo .mcp.json en su raíz: nombra el servidor, da su URL y lleva la key del usuario en el header. Cuando el plugin está habilitado, el host se conecta y las herramientas del servidor aparecen ante el agente.
{
"mcpServers": {
"my-api": {
"type": "http",
"url": "https://api.yourdomain.com/mcp",
"headers": { "Authorization": "Bearer ${MY_API_KEY}" }
}
}
}
El servidor es remoto por diseño: la lógica, los datos y los secretos quedan en infraestructura que controlas, y el plugin solo envía ese puntero. Eso hace que el alcance sea duradero y, en el Concepto 10, controlable y vendible. El plugin es un cliente delgado; el valor vive detrás de la URL. La key en ese header es tu puerta más simple: tu servidor la revisa, y una key cancelada deja de funcionar. Cualquier cosa más sólida ya es sign-in, que conociste en el curso de connectors, y el siguiente curso, AI Identity, trata de dar acceso acotado a agentes. Aquí no lo necesitas.
Entonces, ¿de dónde sale el servidor? Del que ya construiste. Abre tu connector del curso anterior, pide a tu agente que lo ejecute y copia la URL que imprime en el .mcp.json de arriba. Mismo servidor, segunda puerta de entrada: el connector servía a la app de chat; este plugin sirve al agente de código. ¿No tienes un connector a mano? El starter trae un servidor pequeño y ejecutable en reference/server/ para cablear contra él. En cualquier caso apuntas a un servidor; nunca escribes uno dentro del plugin.
¿Por qué no un servidor local?
Claude Code también admite servidores MCP locales (un command que el host ejecuta como proceso en la máquina del usuario). Los saltamos a propósito. Un servidor local envía su código con el plugin y corre en el equipo de otra persona, copiable como una skill y con un runtime que no posees. Para un plugin, un servidor remoto casi siempre es la decisión correcta: constrúyelo y hospédalo una vez, luego apunta tantos plugins como quieras a él por URL.
Algo se mantiene en ambos casos: ese servidor ejecuta tu código y guarda tus secretos. Enviar un plugin que lo cablea lo vuelve parte de la confianza que envías (invariante 4), ahora extendida también a tus usuarios.
✓ Checkpoint: palancas de capacidad cubiertas. Las skills agregan conocimiento, los subagentes agregan ayuda enfocada, los servidores MCP agregan alcance; y las tres son orientativas: el modelo decide cuándo usarlas. Ahora viene la palanca que no es opcional.
Parte 3: la palanca determinista
Concepto 7: hooks, código que se ejecuta cada vez
Un hook es un comando que el host ejecuta automáticamente en un punto fijo del ciclo de vida del agente. No es una sugerencia para el modelo; es tu código, ejecutado por el host, en un calendario que el modelo no puede cambiar. Esa propiedad es la razón por la que los hooks importan más de lo que parece al principio.
Los puntos del ciclo de vida (eventos) caen en tres cadencias:
- Una vez por sesión:
SessionStart,SessionEnd. - Una vez por turno:
UserPromptSubmit(antes de que el agente vea un nuevo prompt),Stop(cuando el agente termina). - En cada llamada a herramienta:
PreToolUse(antes de que una herramienta se ejecute; el único punto que puede bloquearla) yPostToolUse(después).
Un hook de comando funciona igual cada vez: el host le envía una descripción JSON del evento por standard input; tu script la lee, hace su trabajo y responde con un código de salida.
- Exit 0: permitir / hecho.
- Exit 2 en
PreToolUse: bloquear la llamada a la herramienta. Lo que escribas en standard error se entrega al modelo como razón, para que pueda ajustar. - Cualquier otro valor distinto de cero: error no bloqueante; se registra, pero la acción continúa.

Esa regla de exit 2 es todo el juego para guardrails, y es lo que más suele fallar la gente (exit 1 no bloquea). En un plugin, los hooks viven en hooks/hooks.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/format.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Read|Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/block-secrets.sh"
}
]
}
]
}
}
El matcher es un patrón para decidir en qué herramientas se dispara el hook (Write|Edit = escrituras de archivos; Bash = comandos de shell). La variable de ruta de la raíz del plugin apunta a la carpeta del plugin para que el host encuentre tus scripts: confirma su nombre exacto contra tu versión de Claude Code (el SDK y las rutas de plugin se mueven).
Concepto 8: lo obligatorio es un hook, no una instrucción
Esta es la idea más importante del curso. Todo lo que escribes como instrucciones, una skill o una línea de CLAUDE.md, es orientativo. El modelo suele seguirlo, pero puede olvidarlo, quedarse sin contexto o decidir que la conversación ya cambió. Para la mayoría de la guía, eso está bien. Para cualquier cosa que debe cumplirse cada vez, el consejo no basta. Un hook sí.
Dos patrones concentran casi todo el valor real:
Formatear al escribir: PostToolUse. Después de cada edición de archivo, ejecuta tu formateador. La salida del modelo ya no tiene que estar perfectamente estilizada, porque el formateador la normaliza cada vez:
#!/usr/bin/env bash
# hooks/format.sh — runs after every Write/Edit
path=$(jq -r '.tool_input.file_path // empty') # read the edited file's path from the event
[[ -n "$path" ]] && npx --yes prettier --write "$path" 2>/dev/null
exit 0
Bloquear lo que nunca debe pasar: PreToolUse, exit 2. Inspecciona la llamada a herramienta; si cruza una línea, bloquéala y dile al modelo por qué. Esta guarda cubre tanto archivos secretos como comandos destructivos, así que lee dos campos del evento:
#!/usr/bin/env bash
# hooks/block-secrets.sh — runs before Read/Edit/Write/Bash
input=$(cat) # read the event ONCE (see note)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // empty')
if [[ "$path" == *.env* || "$path" == */secrets/* ]]; then
echo "Blocked: $path is a secret file. Do not read or edit it." >&2 # stderr → the model
exit 2 # exit 2 → blocked
fi
if [[ "$cmd" == *"rm -rf"* || "$cmd" == *"git push --force"* ]]; then
echo "Blocked: refusing to run a destructive command ($cmd)." >&2
exit 2
fi
exit 0
La trampa de una línea: lee el evento UNA VEZ
El host envía el evento por standard input, y standard input es un stream: lo primero que lo lee lo vacía. Si llamas jq dos veces directamente (path=$(jq …) y luego cmd=$(jq …)), la primera llamada consume todo el evento y la segunda no recibe nada, así que cmd queda silenciosamente vacío y tu guarda de comandos nunca se dispara. Captúralo una vez con input=$(cat) y analiza esa variable, como arriba. Es el bug exacto que atrapa la prueba del starter: habría enviado una guarda que parece correcta y falla en silencio ante rm -rf.
Una skill que dice "nunca leas .env" es una esperanza. Este hook es una garantía.
Ejecútalo. Pega esto en tu agente de código:
add a
PostToolUsehook that formats files after Write/Edit, and aPreToolUsehook (matched onRead|Edit|Write|Bash) that blocks reads/edits of.env/secrets/and blocksrm -rfin Bash, all with exit 2. Read the event once withinput=$(cat). Then try to read my.envand runrm -rfand show me both are blocked, and edit a file and show me it got formatted.
(Construyes uno aquí para ver la mecánica. En el ejemplo trabajado usarás la versión ya probada del starter en lugar de reescribirla. Construirlo una vez tú mismo es la forma de confiar en él.)
Ejecútalo tú mismo en una terminal (comandos crudos). Prueba un hook como lo llama el host: pásale un evento falso por pipe y revisa el código de salida:
echo '{"tool_input":{"file_path":"/app/.env"}}' | ./hooks/block-secrets.sh; echo "exit: $?" # expect: exit 2
echo '{"tool_input":{"command":"rm -rf /"}}' | ./hooks/block-secrets.sh; echo "exit: $?" # expect: exit 2
echo '{"tool_input":{"file_path":"/app/main.ts"}}' | ./hooks/block-secrets.sh; echo "exit: $?" # expect: exit 0
Verifica. Los tres códigos de salida coinciden: .env bloqueado (2), rm -rf bloqueado (2), archivo normal permitido (0). Si la lectura secreta pasa, tu hook sale con 1 en lugar de 2: el error más común. Si rm -rf pasa pero .env se atrapa, estás leyendo stdin dos veces (mira la trampa anterior). Exit 2 y leer una sola vez, o no bloquea.
✓ Checkpoint: la palanca determinista funciona. Puedes hacer que algo ocurra en cada edición, y detener algo en cada llamada a herramienta. Esa es la diferencia entre un plugin que sugiere y uno que impone.
Cuando un hook se comporta mal (la parte que las guías omiten)
Los hooks se ejecutan en cada llamada a herramienta que coincide, así que uno defectuoso se siente de inmediato. Cuatro reglas los mantienen fuera de tu camino:
- Mantenlos rápidos. Un hook
PreToolUsebloquea el paso de cada llamada coincidente, así que la lógica lenta (un viaje de red, una suite completa de pruebas en cada edición) detiene al agente. Apunta a bastante menos de un segundo; deja el trabajo pesado paraStop, no para cada llamada. - Falla de forma segura, a propósito. Decide qué ocurre cuando el hook mismo falla. Un formateador que no puede ejecutarse debería salir con 0 (deja la edición en pie); por eso
format.shtermina enexit 0y silencia los errores de prettier. Una guarda es lo contrario: si no puede decidir, prefiere bloquear. Nunca dejes que una guarda que crashea caiga silenciosamente a exit 0. - Di por qué cada vez que bloquees. Un exit 2 desnudo sin mensaje no le da al modelo nada sobre lo que actuar, y reintentará lo mismo. La línea en
stderres la instrucción de corrección: hazla específica ("edita la fuente, no el archivo generado"). - Depúralo como lo llama el host. Pasa un evento falso por pipe y lee el código de salida (la prueba con comandos crudos de arriba). Si un hook parece dispararse demasiado, revisa el
matcher:Write|Edites estrecho; un matcher vacío o muy amplio dispara todo.
Parte 4: enviarlo
Concepto 9: el manifiesto y la estructura
Un plugin de Claude Code es una carpeta descrita por un manifiesto, .claude-plugin/plugin.json. (Claude Code puede descubrir automáticamente las carpetas estándar de componentes incluso sin él, pero envía el manifiesto: contiene tu nombre, versión y descripción.)
{
"name": "agent-factory",
"description": "A portable skill, guard hooks, and a reviewer subagent.",
"version": "1.0.0",
"author": { "name": "Your Name" }
}
Todo lo demás va en la raíz del plugin (no dentro de .claude-plugin/; ese es el error estructural que comete mucha gente):
agent-factory/
├── .claude-plugin/
│ └── plugin.json # the manifest (this, and only this, goes here)
├── skills/ # skills as <name>/SKILL.md
├── agents/ # subagent definitions
├── hooks/
│ └── hooks.json # event → command wiring
└── .mcp.json # optional: MCP servers to load
version importa para las actualizaciones: cuando lo aumentas, los instaladores reciben la versión nueva; si lo omites y distribuyes por git, cada commit cuenta como una versión nueva. Ejecuta claude plugin validate antes de compartir: es la misma revisión que corre el marketplace.
El árbol de arriba es el plugin en sí, donde sea que esté. En el starter vive en plugins/agent-factory/ dentro de un repositorio de marketplace, que es el siguiente concepto.
Concepto 10: marketplaces, cómo lo recibe un compañero
Un marketplace es solo un repositorio git con un archivo de catálogo (marketplace.json) que lista uno o más plugins. Esa es toda la historia de distribución: no publicas un paquete en un registry; apuntas a la gente a un repositorio.
{
"name": "agent-factory",
"owner": { "name": "Your Name" },
"plugins": [
{
"name": "agent-factory",
"source": "./plugins/agent-factory",
"description": "A portable skill, guard hooks, and a reviewer."
}
]
}
Entonces un compañero ejecuta dos comandos dentro de Claude Code:
/plugin marketplace add your-org/agent-factory # the git repo with marketplace.json
/plugin install agent-factory@agent-factory # plugin@marketplace
Mientras desarrollas, salta el marketplace. Tienes dos bucles más rápidos en tu propia máquina: carga el plugin directamente desde disco con claude --plugin-dir ./plugins/agent-factory (también acepta un .zip), o crea uno con claude plugin init <name>, que lo deja en ~/.claude/skills/<name>/ y lo autocarga en la siguiente sesión como <name>@skills-dir, sin marketplace ni instalación. El marketplace es para compartir; no lo necesitas para construir y probar.
No confundas los dos manifiestos. Un plugin tiene .claude-plugin/plugin.json; un marketplace tiene .claude-plugin/marketplace.json. La estructura documentada los mantiene separados: marketplace.json va en la raíz del repositorio, y cada plugin vive en su propia subcarpeta (./plugins/<name>/) con su propio plugin.json. El starter usa exactamente esto: plugins/agent-factory/. (Un repositorio puede ser marketplace y alojar un plugin, pero mantener el plugin en una subcarpeta ./plugins/<name> es el patrón que usan todos los ejemplos oficiales: prefierelo.)
Pinning y sources: cómo funcionan realmente las actualizaciones. El source de un plugin puede ser una ruta relativa (arriba) o un objeto que apunta a otro repositorio; un marketplace puede listar plugins de muchos repositorios, cada uno fijado de forma independiente:
{
"name": "code-formatter",
"source": { "source": "github", "repo": "acme/formatter", "ref": "v2.1.0" }
}
ref fija una rama o etiqueta, sha fija un commit exacto, y cuando ambos existen, sha gana. Eso, no el archivo de catálogo en sí, es cómo un compañero recibe una versión específica y cómo envías actualizaciones. (Un source url cubre GitLab y otros hosts git; una ruta local sirve para pruebas.)
Dos trampas antes de publicar:
- Las rutas relativas solo se resuelven cuando el marketplace se añade por Git (GitHub/GitLab/URL git). Si alguien lo añade mediante una URL directa al archivo
marketplace.json,./plugins/...no se resolverá; usa entonces un sourcegithubourl. - Los plugins instalados se copian a una caché, así que un plugin no puede alcanzar archivos fuera de su carpeta con
../. Mantén dentro del plugin todo lo que necesita; los symlinks se siguen durante la copia siempre que apunten dentro del plugin, por eso los dos symlinks del starter apuntan a archivos propios del plugin.
Anthropic mantiene sus propios catálogos oficiales, claude-plugins-official (curado) y el comunitario claude-community (agregas su repo anthropics/claude-plugins-community y lo instalas como @claude-community), así que elige un nombre distinto para tu marketplace en lugar de pisar esos nombres. (Las reglas de nombres y envío son jóvenes; confirma la política actual de nombres reservados contra la referencia de plugins antes de publicar.)
Distribuir a un equipo o a no programadores. En planes Team y Enterprise, los propietarios publican un marketplace desde Organization settings → Plugins; se añade por defecto un marketplace de Knowledge Work, y los plugins que distribuyes aparecen en chat y en Claude Cowork: el mismo paquete llega a knowledge workers, no solo a builders (mira el techo y el curso Cowork and OpenWork).
Ejecuta claude plugin validate antes de compartir. El esquema anterior está vigente a mediados de 2026; vuelve a verificar los nombres de campos contra la referencia de plugins de Claude Code antes de publicar, porque esta superficie es joven y se mueve.
¿Puedes cobrar por él? Sí, pero no por los archivos. Un marketplace es un catálogo, no una tienda: el formato no trae capa de pago, revisión de licencia ni primitiva de suscripción. La facturación y el control de acceso los construyes tú, fuera del sistema de plugins. Y hay un borde claro: una skill es un SKILL.md en texto plano, sin DRM. En cuanto un cliente la instala, tiene tu fuente, así que poner archivos estáticos detrás de una suscripción invita a un solo churn por cliente (paga una vez, clona, cancela). Para un currículo donde el valor es el texto legible, entregas la IP en la primera descarga.
Por eso el único modelo que sostiene una suscripción real es el acceso hospedado: deja la lógica valiosa en un servidor que controlas y vende entrada al servidor, no a los archivos. El plugin instalado es un cliente delgado y gratuito cuyo .mcp.json apunta a tu servidor MCP hospedado con la key del usuario en el header (el cableado del Concepto 6); la key es la puerta de suscripción, y revocarla corta el acceso de inmediato. El SKILL.md gratuito es el funnel; el moat pagado es lo que un clon no puede copiar: el servidor hospedado, la calidad de retrieval y los datos vivos detrás de la URL.
Esta es la versión para plugins de un patrón que ya construiste. Una app connector-native no tiene el problema de archivos copiables, porque es un servidor hospedado puro, sin nada en el disco del usuario. La forma limpia es usar ambos: el plugin gratuito como cliente y funnel, y la suscripción sobre el servidor connector-native que está detrás. El mismo servidor, una segunda puerta de entrada. También corta en ambas direcciones: tus usuarios ahora confían sus solicitudes a tu servidor, así que el contrato de confianza corre en los dos sentidos (Concepto 11).
Dos advertencias antes de cobrar
- No rompas las políticas de uso de Anthropic. Si los estudiantes consumen Claude a través de tu servicio hospedado, la licencia y facturación de ese uso deben ser legítimas; es la misma razón por la que enrutar una suscripción personal Pro/Max hacia herramientas de terceros es problemático. Si esto se convierte en ingresos reales, lee directamente los términos comerciales de Anthropic (no un blog) y confirma la ruta de facturación para el uso de Claude que dispara tu servidor.
- Hospedar significa que posees la superficie de seguridad. Un servidor MCP pagado y con control de acceso es un objetivo de ataque, y los clientes que pagan esperan estabilidad. Por tanto, los permisos de herramienta y las confirmaciones para cualquier acción de escritura, borrado o red dejan de ser opcionales. Es el invariante 4, ahora con dinero encima.
Paso solo humano. Crear el repositorio git y enviarlo a un marketplace es tu trabajo; tu agente de código escribe los archivos, pero no puede abrir cuentas ni hacer push en tu nombre. También lo es el /plugin install que ejecuta tu compañero: esa es su decisión de confianza (siguiente concepto).
Concepto 11: un plugin se ejecuta dentro de la confianza del usuario
Da un paso atrás y mira qué puede hacer un plugin en el equipo que lo instala: sus hooks ejecutan comandos de shell, su bin/ se añade al path, sus servidores MCP se ejecutan y salen a la red. Instalar un plugin es ejecutar código de otra persona. Eso funciona en ambos sentidos, y ambos son tu trabajo:
-
Como autor: privilegios mínimos. Solo los hooks que necesitas, con matchers tan estrechos como sea posible. No alcances la red ni el sistema de archivos más allá del trabajo. Y haz legible la confianza: envía un README que diga, en palabras claras, qué hace el plugin en el equipo del instalador:
README.md — the trust contract
What this plugin installs (skills, subagents, hooks, MCP servers)
What hooks run, and when (e.g. PostToolUse formatter on Write/Edit)
What files they inspect (e.g. reads tool_input.file_path; never opens .env)
What commands they execute (e.g. prettier; no network calls)
What network access they use (ideally: none)Un instalador que puede leer eso en diez segundos puede confiar en ti en diez segundos.
-
Como instalador: revisa antes de instalar, como revisarías una dependencia. Prefiere marketplaces en los que confías; lee qué hacen los hooks; recuerda que un hook
PreToolUseve cada llamada a herramienta. Antes de confiar en uno, ejecutaclaude plugin details <plugin>: imprime el inventario de componentes (qué skills, subagentes, hooks y servidores MCP incluye) y el costo proyectado en tokens, sin habilitar nada. Los hooks son la línea que debes leer primero.
Este es el invariante 4, y no es papeleo: un hook de formato que subiera tus archivos en silencio sería invisible hasta que lo leyeras. Envía plugins que te sentirías cómodo instalando.
✓ Checkpoint: puedes enviarlo. Manifiesto, estructura, marketplace desde el que un compañero instala y una mirada clara a la confianza que estás enviando. Un host más, luego la construcción completa.
Parte 5: plugins de OpenCode
Concepto 12: plugins de OpenCode, hooks como código
OpenCode toma las mismas ideas de otra forma: un plugin es un módulo JavaScript/TypeScript que exporta una función. El host llama a tu función con un objeto de contexto y tú devuelves hooks, handlers para los eventos del agente. No hay manifiesto separado; dejas el archivo en .opencode/plugins/ (o instalas un paquete npm).
Verifica esta sección contra tu versión. La API de plugins de OpenCode es más joven y más cercana al código que la forma declarativa de Claude Code, así que los nombres y firmas exactos de eventos (tool.execute.before, session.idle, el helper tool) se mueven más rápido que el resto de este curso. Están vigentes a mediados de 2026, pero revísalos contra tu @opencode-ai/plugin instalado antes de enseñar o enviar algo desde esta sección.
Una diferencia clave frente a Claude Code: en OpenCode, un plugin sirve para hooks y herramientas, no para skills. OpenCode descubre skills de forma nativa desde directorios (.opencode/skills/, .claude/skills/, .agents/skills/), así que tus archivos portables SKILL.md no necesitan plugin ni shim aquí. El plugin existe para la parte que no se porta: los hooks.
// .opencode/plugins/block-secrets.ts
import type { Plugin } from "@opencode-ai/plugin";
export const BlockSecrets: Plugin = async ({
project,
client,
$,
directory,
}) => {
return {
// runs before any tool — throw to block it (the OpenCode equivalent of exit 2)
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath?.includes(".env")) {
throw new Error("Blocked: .env files are off-limits.");
}
},
};
};
El modelo mental se mapea directamente desde Claude Code: tool.execute.before es tu PreToolUse, tool.execute.after es tu PostToolUse, y lanzar un error bloquea la llamada del mismo modo que exit 2. OpenCode también dispara eventos de sesión y archivo (session.idle, file.edited, y más), y un plugin puede añadir una herramienta personalizada con el helper tool: la misma idea de "añadir alcance" que en un servidor MCP, escrita inline.
El objeto de contexto te da lo que necesitas: project y directory (dónde estás), $ (ejecutar comandos de shell) y client (hablar con el agente, registrar). La forma cambia; los cuatro invariantes no. Una regla obligatoria sigue siendo un hook aquí: solo que es una función que lanza error en lugar de un script que sale con 2.
Parte 6: un ejemplo completo: construir el plugin agent-factory
Ya ejecutaste el agent-factory terminado en el Quick Win. Ahora lo construyes tú, desde blanco, palanca por palanca, dirigiendo a tu agente en inglés claro. Cuando una pieza vuelva mal, la comparas con reference/, la build probada que acabas de instalar. No estás rellenando stubs; estás tomando decisiones (qué palanca, esperanza o garantía, qué viaja) y probando cada una. El ritmo es el que ya conoces: plan → revisión → ejecución → verificación.
Cuando termines, tu agent-factory muestra las cuatro palancas: una skill portable para un trabajo real, un subagente reviewer, un hook de guarda más un hook de formato al escribir, un servidor MCP cableado por URL y una entrada de marketplace que un compañero instala. La guarda obligatoria va primero, porque es la parte que debe estar bien.
1. Scaffold del plugin vacío. El prompt apunta tu agente al layout autoritativo de tu host. Pega el que corresponda:
Using the Plugin Structure skill you installed in setup, scaffold an empty plugin called agent-factory, set up the right way for Claude Code. Show me the layout.
Read the OpenCode plugin docs at https://opencode.ai/docs/plugins, then scaffold an empty OpenCode plugin called agent-factory the way they describe. Show me the layout.
Hecho cuando: el shell coincide con el layout de tu host (tu agente puede compararlo contra la referencia si duda). En Claude Code, claude plugin validate pasa sobre el plugin vacío.
2. Construye primero el hook de guarda, la palanca obligatoria, y demuestra que bloquea. Esta es la parte que debe estar bien, así que la construyes, la pruebas y luego la revisas contra la versión probada. Pega:
Add two house rules my agent can't skip: auto-format any file right after it's changed, and hard-block anything that reads my secrets or runs a destructive command. Prove both live: have it try a secret read and a destructive command and show me they're stopped, then edit a file and show me it came back formatted.
Luego revisa tu trabajo contra la build probada en vez de confiar en él:
Compare my guard against the proven one and tell me if I missed anything that would keep it from actually blocking.
Hecho cuando: la guarda bloquea .env y un comando destructivo en vivo, y la comparación contra la referencia no encuentra nada importante. (La guarda toma una forma distinta en cada host: un script de shell en Claude Code, una función que lanza error en OpenCode; la referencia trae ambas. Tu agente construye la que usa tu host.)
3. Construye una skill para un trabajo que realmente tengas. No una demo: elige algo repetitivo de verdad, como tu checklist de review, el formato de commits o tus pasos de release. Pega:
Look at the model skill in the reference build first. Then write me a skill for [a real, repetitive job you do]: a clear description of when to use it and the steps to follow. Keep it portable so it works in any agent, not just this one. Show it firing on a real example.
Hecho cuando: la skill se activa sola cuando la tarea encaja, y su cuerpo es portable (tu agente la dejó como instrucciones claras, sin constructos específicos de una herramienta).
4. Agrega un subagente reviewer. Pega:
Add a subagent that reviews a change in its own context and only reports, never edits. Run it on a real diff, show me what it finds, then compare it to the model reviewer.
Hecho cuando: el subagente revisa en un contexto limpio y reporta una lista ordenada; la comparación contra la referencia no muestra nada importante faltante.
5. Cablea el servidor MCP, apunta tu plugin a uno en ejecución. No escribes el servidor. Apuntas a uno que ya tienes: el connector que construiste en el curso anterior o el sample ejecutable del starter. Pega:
Start the sample MCP server in the starter and wire my plugin to it, then show me the agent can call one of its tools.
(¿Prefieres el tuyo? Dile a tu agente que ejecute el connector del curso anterior y use esa URL.) El cableado que escribe tu agente es el lugar donde los dos hosts realmente difieren; esta es la forma en cada uno:
Envía un .mcp.json en la raíz del plugin (viaja con el plugin):
{
"mcpServers": {
"agent-factory": {
"type": "http",
"url": "http://localhost:3000/mcp",
"headers": { "Authorization": "Bearer ${AGENT_FACTORY_KEY}" }
}
}
}
Confirma con /mcp: el servidor aparece conectado y su herramienta se puede llamar.
Agrega un bloque remote a opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"agent-factory": {
"type": "remote",
"url": "http://localhost:3000/mcp",
"enabled": true
}
}
}
Hecho cuando: tu host muestra el servidor conectado y su herramienta se puede llamar.
6. Hazlo instalable y demuestra que viaja. Pega:
Make this installable from a marketplace. Then prove it travels: install it into a different project and show the guard blocks a secret read there too, with no extra setup.
Hecho cuando: un segundo proyecto queda protegido por el mismo hook mediante una instalación. Ese es el punto completo de un plugin: la regla viaja.
Observa el ritmo: plan → revisión → ejecución → verificación, con la guarda obligatoria construida y probada primero porque es la parte que debe estar bien, y cada pieza comparada contra la referencia. El juicio fue tuyo todo el tiempo; el agente escribió.
Parte 7: el techo y dónde crece
Concepto 13: el techo y los puentes hacia fuera
Siente el borde de lo que es un plugin. Un plugin mejora el agente del builder: más preciso, más seguro, más tuyo. Pero tres cosas aún no son tuyas, y cada una nombra el siguiente curso.
El loop no es tuyo. Tus hooks se disparan alrededor del loop del host; no ejecutan un loop propio. Un plugin no puede despertarse, perseguir una meta a través de muchos pasos por su cuenta ni hacer un trabajo mientras duermes. Cuando quieres un worker que posea su loop, escribes el agente: eso es Build AI Agents, más adelante en la ruta.
La identidad no es tuya. Tu plugin actúa como la persona que ejecuta el host. No tiene credencial propia ni forma de actuar en nombre de alguien con autoridad acotada y revocable. Cuando un agente necesita su propia identidad, y una persona necesita delegarle autoridad con seguridad, eso es AI Identity (sobre Better Auth): poseer el sign-in y luego dar al agente acceso con scope, límite de tiempo y aprobación humana.
El alcance es prestado. Un plugin puede cablear un servidor MCP remoto, pero el servidor en sí, la cosa duradera y de cara al usuario que una persona desconocida pega en la app de chat, con su propio estado y sign-in, es la app connector-native que construiste en el curso anterior. Plugins y connectors apuntan al mismo servidor desde dos hosts; juntos cubren ambos.
Pero observa hacia dónde corren los límites y dónde crece. Lo que construiste llega más allá del agente de código. Dentro de la familia Anthropic, el mismo bundle .claude-plugin también carga en Claude Cowork y claude.ai chat; un plugin de OpenCode también carga en OpenWork. Y la pieza portable, la skill, viaja aún más lejos, a un agente personal como OpenClaw y más. Así que la skill que escribiste para el agente de un builder puede moverse, sin cambios, al agente de un knowledge worker: abogado, analista, líder de operaciones. (El hook de shell es la excepción. Necesita una shell real, así que una guarda queda del lado de código mientras la skill cruza a los hosts de chat.) Cuando esos hosts de knowledge work son toda la historia y no un bonus, eso es su propio curso: Cowork and OpenWork.
No desperdiciaste un paso. Aprendiste a extender un agente de forma determinista y enviarlo a un equipo: las mismas skills que reutilizarás cuando el agente, y su identidad, sean tuyos.
El mismo esqueleto, otros plugins
agent-factory es una forma. Las palancas no cambian; solo cambia el trabajo:
- Un plugin de estilo de casa: una skill con tus convenciones de escritura o código, un formatter
PostToolUse, un subagente reviewer. (Para un equipo que quiere una voz consistente.) - Un plugin de seguridad: guardas
PreToolUsepara objetivos de producción, secretos y comandos destructivos; nada más. (Privilegio mínimo, invariante 4.) - Un plugin de servicio: un servidor MCP remoto (
.mcp.json) para tu API hospedada, más una skill que enseña al agente a usarlo. - Un plugin de workflow: un hook
Stopque ejecuta tu suite de tests cuando el agente termina, y una skill para tus pasos de release.
Elige el más cercano a un dolor real de tu equipo; la construcción es la misma que en el ejemplo trabajado.
Capstone
Envía un plugin propio. Elige una fricción real en cómo tu equipo trabaja con un agente de código. Construye un plugin que la corrija con las palancas correctas: al menos un hook que imponga una regla obligatoria (exit 2 o un error lanzado), y al menos una palanca de capacidad (skill, subagente o servidor MCP). Publícalo en un marketplace y haz que alguien más lo instale. Confirma que el hook se dispara para esa persona, en su proyecto, sin configuración extra.
Discuss with an AI. Question your scores.
Come back when you have your BEST evaluation.