Versionado, compatibilidad y conformidad

Por: Artiko
agent-skillsplugins-de-agentesia-agentesagent-pluginsversionadosemverconformidadcompatibilidad

Versionado, compatibilidad y conformidad

En un plugin conviven dos relojes distintos que se parecen mucho y que no significan lo mismo:

  1. La versión de la especificación a la que apunta el paquete. Vive en el campo $schema de plugin.json y, si existe, también en el $schema de mcp.json.
  2. La versión de tu plugin. Vive en el campo opcional version del manifiesto.

Cada uno tiene reglas y consecuencias propias cuando algo no calza. Este capítulo separa los dos relojes, extrae la lista completa de requisitos de conformidad de cada rol —paquete y cliente— y cierra con una estrategia de evolución para un plugin propio. Lo que venga de FUTURE_CONSIDERATIONS.md, del apéndice A o de Design Decisions se marca como no normativo.

flowchart TD
    A["plugin.json"] --> B["$schema — versión de la ESPECIFICACIÓN"]
    A --> C["version — versión de TU PLUGIN"]
    B --> D["Selecciona reglas de validación e interpretación en el cliente"]
    B --> E["Si mcp.json existe, DEBE declarar la misma versión"]
    C --> F["El cliente PUEDE usarla para actualizaciones y frescura de caché"]
    C --> G["El cliente NO DEBE rechazar el manifiesto por no ser SemVer"]

1. Cómo se versiona la especificación

1.1 Una versión cubre tres artefactos

La sección 10.1 es tajante: la versión declarada en la sección 1 identifica el release completo de la especificación, y eso incluye tres cosas a la vez: el texto normativo, el esquema del manifiesto (plugin.schema.json) y el esquema de configuración MCP (mcp.schema.json). Y añade una regla que sorprende a quien viene de otros ecosistemas:

“Every specification release MUST publish both schemas with the same version as the specification, even when a schema’s validation rules are unchanged from the previous release.”

Es decir: cada release DEBE (MUST) publicar los dos esquemas con la misma versión que la especificación, aunque las reglas de validación de uno de ellos no hayan cambiado. No existen tres líneas de versión independientes; hay una sola.

El apartado no normativo Why do schemas share the specification version? explica el motivo: darle a autores y clientes una sola versión del formato portable que entender, impedir paquetes de versiones mezcladas y permitir que $schema seleccione el contrato completo de validación e interpretación, incluidos los requisitos que JSON Schema no puede expresar.

1.2 $schema es un selector de versión, no una descarga

El $schema obligatorio de plugin.json identifica la versión de Agent Plugins a la que apunta el paquete. Para 1.0.0 su valor DEBE ser exactamente el identificador canónico:

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "minimal-plugin"
}

Y las reglas del cliente son estas, literales de la sección 5.2:

  • El cliente DEBE (MUST) usar un valor de $schema reconocido para seleccionar las reglas de validación e interpretación soportadas localmente.
  • El cliente PUEDE (MAY) mapear varios identificadores canónicos a la misma implementación, pero solo cuando reconoce explícitamente esas versiones de Agent Plugins como compatibles.
  • El cliente NO DEBE (MUST NOT) recuperar un esquema mientras carga un plugin.
  • Si el cliente no soporta la versión declarada ni una versión explícitamente reconocida como compatible, DEBE rechazar el plugin y DEBERÍA (SHOULD) reportar la versión no soportada.

Esa tercera regla define la naturaleza del campo: la URL nunca se descarga. Es un identificador opaco que actúa como llave de un diccionario local de implementaciones. Un cliente sin red carga un plugin igual de bien.

La sección 7.2.1 repite palabra por palabra el mismo trío de reglas para el $schema de mcp.json, cuyo identificador canónico en 1.0.0 es https://agent-plugins.org/schemas/1.0.0/mcp.schema.json.

1.3 Las dos versiones del paquete deben coincidir entre sí

Cuando un plugin trae mcp.json, la versión de su $schema DEBE coincidir con la versión declarada por plugin.json. Un desajuste tiene una consecuencia muy acotada:

“A mismatch makes the MCP configuration invalid under §7.2.2 but does not invalidate other component types.”

Traducido a comportamiento observable: si tu plugin apunta a 1.0.0 en plugin.json y a otra versión en mcp.json, el cliente DEBE deshabilitar MCP para ese plugin, DEBERÍA reportar el desajuste y seguirá cargando tus skills. El plugin no muere; pierde una pata. Es el mismo principio de fronteras de fallo estrechas del capítulo de descubrimiento y carga.

1.4 Los identificadores canónicos son inmutables

Dos reglas cierran el modelo: un cambio en cualquiera de los dos esquemas requiere un nuevo release de la especificación, y los identificadores canónicos ya publicados NO DEBEN (MUST NOT) ser reasignados a contenidos de esquema distintos. Una vez que https://agent-plugins.org/schemas/1.0.0/plugin.schema.json describe un conjunto de reglas, queda amarrado a ellas para siempre, y un cliente puede cachear esa interpretación sin miedo a que el significado cambie bajo sus pies.

La contrapartida para los autores es generosa: los plugins existentes PUEDEN (MAY) seguir apuntando a una versión antigua. No hay caducidad forzada en el formato; los clientes deciden qué soportan con los identificadores canónicos declarados y sus mapeos explícitos de compatibilidad.

flowchart TD
    A["El cliente lee $schema de plugin.json"] --> B{"¿Identificador reconocido localmente?"}
    B -- No --> C["Rechaza el plugin y DEBERÍA reportar la versión no soportada"]
    B -- Si --> D["Selecciona las reglas de validación de esa versión"]
    D --> E{"¿Existe mcp.json?"}
    E -- No --> F["Ausencia de ubicación fija: no es error"]
    E -- Si --> G{"¿Su $schema declara la misma versión?"}
    G -- No --> H["Deshabilita MCP para ese plugin y sigue cargando skills"]
    G -- Si --> I["Valida mcp.json y cada entrada de servidor por separado"]

2. Qué significa exactamente 1.0.0

La cabecera declara **Spec Version: 1.0.0** y **Status: Published**. La sección 1 fija el alcance del compromiso:

“Clients and plugin packages claiming conformance to Agent Plugins v1 MUST implement or follow the requirements in this document.”

Nótese la simetría: la obligación cae por igual sobre clientes y sobre paquetes de plugin. No es una especificación que solo regule runtimes; el paquete también tiene requisitos que cumplir, y la sección 3 los enumera todos.

2.1 Lo que 1.0.0 sí garantiza

Un plugin que declare 1.0.0 y respete el documento puede contar con que cualquier cliente conformante:

GarantíaSección
Buscará el manifiesto en plugin.json en la raíz del plugin§5.1
Validará el manifiesto contra un esquema cerrado de 10 campos§5.2
Descubrirá skills en skills/, solo en hijos inmediatos con SKILL.md§6.1, §7.1
Descubrirá servidores MCP únicamente en mcp.json de la raíz§6.1, §7.2
No tratará como error la ausencia de una ubicación fija§6.2
Ignorará los namespaces de extensions que no implemente, sin validarlos§8.1
Rechazará cualquier ruta de paquete que resuelva fuera de la raíz del plugin§4.1
Si lanza subprocesos, proveerá PLUGIN_ROOT y PLUGIN_DATA§9.1
Expandirá ${PLUGIN_ROOT} y ${PLUGIN_DATA} solo en args, env y cwd§9.2
No hará que el fallo de un componente tumbe a los demás§11.3

2.2 Lo que 1.0.0 explícitamente no cubre

FUTURE_CONSIDERATIONS.md es no normativo y aclara que ninguno de sus puntos es requisito de conformidad ni está comprometido para un release futuro. Con esa advertencia, lo que allí se reconoce como ausente en 1.0.0 es:

  • Permisos y UX de aprobación: no hay modelo de confianza, ni sistema de permisos, ni requisitos de sandboxing.
  • Verificación de procedencia: no hay firmas criptográficas ni atestación.
  • Manejo de secretos: no hay campo secrets ni inyección mediada por el cliente. Por eso la spec prohíbe embeber credenciales en env y headers en vez de ofrecer un mecanismo.
  • Controles empresariales: no hay allowlists, registros de organización ni overrides centralizados.
  • Estandarización de auditoría: hay requisitos de reporte de fallos, pero no un esquema de eventos de ciclo de vida.
  • Resolución de dependencias: no existe campo dependencies.
  • Testing y validación: literalmente “No test harness or validation tool is specified.”

Ese último punto es el que más se malinterpreta: que no exista validador oficial no significa que no puedas validar, sino que la validación la construyes tú con validadores genéricos de JSON Schema, como veremos en el capítulo 8.

La sección no normativa Why only Agent Skills and MCP in v1? explica además por qué el catálogo de componentes es tan corto: skills y MCP tienen especificaciones establecidas fuera de este proyecto y adopción real entre clientes. Comandos, hooks, agentes, reglas y servidores LSP se consideraron demasiado específicos de cada cliente para un contrato portable estable.

3. Conformidad del paquete: la lista completa

Requisitos cuyo sujeto normativo es el plugin, su manifiesto, su configuración o su autor. Cada fila cita la sección de la spec.

3.1 Estructura y manifiesto

NivelRequisito
DEBEUn plugin incluye un manifiesto en plugin.json en la raíz del plugin (§4.1).
DEBEEl manifiesto es JSON y contiene un objeto de nivel superior (§5.2).
DEBETodo campo permitido cumple el tipo y las restricciones definidas (§5.2).
DEBEPara 1.0.0, $schema vale exactamente el identificador canónico del esquema de manifiesto (§5.2).
DEBEEl name cumple las cuatro restricciones de §5.5: 1 a 64 caracteres, solo a-z, 0-9, - y ., primer y último carácter alfanuméricos, sin -- ni .. consecutivos.
PUEDEEl objeto author contiene únicamente name, email y url, cada uno string. Cualquier otro campo o tipo invalida el manifiesto (§5.4).
RECOMENDADOversion usa Versionado Semántico (§5.4).
RECOMENDADOlicense usa un identificador SPDX (§5.4).
DEBEUn campo de configuración definido como ruta relativa al plugin empieza con ./, se resuelve contra la raíz del plugin y permanece dentro de ella tras resolverse (§4.1).

3.2 Componentes

NivelRequisito
DEBELas Agent Skills conforman la Agent Skills specification, que la §7.1 declara fuente de verdad del formato de SKILL.md, sus campos de frontmatter y su layout de directorios (curso de Agent Skills).
NO DEBELa configuración MCP se declara inline en plugin.json ni se carga desde ninguna ruta core alternativa (§7.2.1).
DEBEmcp.json es un objeto JSON con los campos obligatorios $schema y mcpServers, y ningún otro campo de nivel superior (§7.2.1).
DEBEmcpServers es un objeto cuyos nombres de miembro identifican servidores y cuyos valores son objetos de configuración (§7.2.1).
DEBEPara 1.0.0, el $schema de mcp.json vale exactamente el identificador canónico del esquema MCP (§7.2.1).
DEBECada configuración de servidor contiene type y casa exactamente con una de las variantes cerradas (§7.2.1).
DEBEcommand es un único token ejecutable, no una cadena de shell; nombre desnudo o ruta relativa al plugin que empieza con ./ (§7.2.1).
NO DEBEUn plugin que reclama conformidad depende de que un PATH configurado afecte la resolución de un command desnudo (§7.2.1).
DEBEUn plugin que empaqueta un ejecutable usa un command relativo al plugin (§7.2.1).
DEBEcwd, cuando está presente, tiene una de las tres formas admitidas y permanece contenido tras resolverse (§7.2.1).
DEBEurl es una URL absoluta HTTP o HTTPS, sin user-info ni fragmento; los endpoints no loopback usan HTTPS (§7.2.1).
DEBELos nombres y valores de header son campos HTTP válidos (§7.2.1).
NO DEBELos plugins embeben credenciales u otros secretos en headers (§7.2.1).
NO DEBELos plugins embeben credenciales u otros secretos en env (§9.2).
NO DEBEEl env de un servidor MCP contiene entradas llamadas PLUGIN_ROOT o PLUGIN_DATA (§9.2).
NO DEBESalvo la búsqueda de ejecutables de la plataforma para resolver un command desnudo, un plugin conformante depende de una variable del entorno base que la spec no exija ni la configuración de servidor suministre explícitamente (§9.1).

3.3 Extensiones y versionado

NivelRequisito
DEBELos datos de manifiesto específicos de cliente se representan bajo un namespace de dominio inverso en extensions (§8).
DEBELos archivos específicos de cliente se representan bajo un directorio de nivel superior con el nombre de ese namespace (§8).
DEBEextensions es un objeto cuyos nombres de miembro son namespaces y cuyos valores son objetos (§8.1).
DEBESi mcp.json está presente, la versión de su $schema coincide con la declarada por plugin.json (§10.1).
PUEDEUn plugin existente sigue apuntando a una versión anterior de Agent Plugins (§10.1).
DEBERÍAEl plugin usa Versionado Semántico para version (§10.2).

4. Conformidad del cliente: la lista completa

La sección 11.1 abre con la regla general: “A conformant client MUST satisfy all applicable requirements in sections 1–10.” Todo lo anterior aplica. Sobre esa base, el documento enumera ocho capacidades mínimas:

  1. Puede cargar un plugin desde una ruta de directorio.
  2. Selecciona desde $schema un esquema de manifiesto soportado localmente, y luego parsea y valida el esquema cerrado de plugin.json usando las excepciones no fatales de §5.2 y §8.1.
  3. Ignora los miembros no implementados de extensions sin validar el contenido de sus valores.
  4. Para cada tipo de componente que soporta, descubre los componentes en su ubicación fija.
  5. Si soporta servidores MCP, selecciona desde $schema una configuración MCP soportada localmente y soporta al menos una de las variantes stdio o streamable-http de mcp.json.
  6. Si lanza subprocesos de plugin —es decir, servidores MCP stdio— provee PLUGIN_ROOT y PLUGIN_DATA y expande ambas variables en los valores de configuración de runtime: args, env y cwd.
  7. Para servidores MCP stdio, resuelve command como un único token ejecutable y usa la raíz del plugin como directorio de trabajo por defecto del subproceso.
  8. Soporta al menos un tipo de componente: skills o servidores MCP.

4.1 Adopción incremental

La sección 11.2 desactiva la lectura maximalista de esa lista: “A client is not required to support every component type. For example, a skills-only client can conform without supporting MCP servers, provided it satisfies all applicable requirements.”

Un cliente que solo entiende skills es conformante. Y dentro de MCP, DEBE soportar al menos uno de stdio o streamable-http, DEBERÍA soportar ambos, y el soporte de sse es OPCIONAL. La palabra clave del punto 1 de 11.1 es applicable: los requisitos de MCP no aplican a quien no implementa MCP.

4.2 Componentes no soportados y fallos

La sección 11.3 son cuatro reglas cortas que definen el carácter resiliente del formato:

  1. El cliente DEBE ignorar los tipos de componente que no soporta.
  2. Un campo de nivel superior desconocido o un extensions que no sea objeto son no fatales bajo §5.2 y §8.1. Cualquier otra violación del esquema de plugin.json es fatal para el plugin: el cliente DEBE rechazarlo y NO DEBE descubrir ni ejecutar ninguno de sus componentes.
  3. Un fallo aislado a un tipo de componente, a una entrada de componente o a un proceso de componente NO DEBE impedir que el cliente cargue los componentes que sean válidos de forma independiente.
  4. El cliente DEBERÍA reportar configuración inválida y fallos de componente. PUEDE reportar plugins parcialmente soportados, pero la falta de soporte para un tipo de componente, un transporte MCP o una extensión de cliente no es en sí misma un error.

Ese último matiz importa a quien escribe un cliente: no soportar algo no es un fallo que reportar como error, es una decisión de alcance legítima.

4.3 El apéndice A no es la especificación

El documento incluye un Conformance Checklist con 25 casillas repartidas en cinco bloques: plugin loader (7), component discovery (2), MCP configuration (4), environment and expansion (8) y resilience (4). Sirve para auditar una implementación de un vistazo, pero el propio apéndice avisa: “This checklist is for convenience only — when it conflicts with the spec text above, the spec governs.” El apéndice A y Design Decisions son no normativos; todas las demás secciones sí lo son.

5. Extensiones y campos propietarios sin romper la portabilidad

El manifiesto es un esquema cerrado: los únicos campos de nivel superior permitidos son $schema, name, version, description, author, homepage, repository, license, keywords y extensions. Cualquier otro campo raíz no conforma al esquema.

Pero la consecuencia es deliberadamente suave: el cliente DEBE reportar e ignorar cada campo desconocido, DEBE seguir cargando el plugin si el resto del manifiesto cumple, y NO DEBE asignar semántica a campos desconocidos. Un campo inventado en la raíz no rompe el plugin, pero tampoco hace nada: ningún cliente puede interpretarlo sin violar la spec.

La vía correcta para datos propietarios es extensions, con clave de dominio inverso:

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "example-plugin",
  "extensions": {
    "com.example.client": {
      "setting": true
    }
  }
}

Y para archivos propietarios, un directorio de nivel superior con exactamente ese nombre de namespace:

my-plugin/
├── plugin.json
├── skills/
│   └── summarize/
│       └── SKILL.md
└── com.example.client/
    └── hooks/
        └── hooks.json

Reglas de portabilidad que hacen que esto funcione:

  • Agent Plugins no asigna ninguna semántica portable de descubrimiento, validación, carga o fallo a los datos ni a los archivos de extensión. Cada cliente define el contenido y el comportamiento de su propio namespace.
  • Un cliente DEBE ignorar las entradas de manifiesto de namespaces que no implementa, sin validar el contenido de sus valores. Tu bloque com.tuempresa.cliente es invisible e inofensivo para el resto del ecosistema.
  • Un cliente DEBERÍA basar su namespace en un dominio que controle y DEBERÍA mantenerlo estable, y PUEDE usar una de las dos representaciones o ambas.
  • Si extensions no es un objeto, el cliente DEBE reportar e ignorar el campo y continuar cargando componentes: es la segunda —y última— excepción no fatal del manifiesto.

El apartado no normativo Why reverse-domain client extensions? lo resume: los identificadores de dominio inverso dan una convención descentralizada para evitar colisiones sin necesitar un registro central de nombres de cliente.

flowchart TD
    A["Necesitas declarar algo que la spec no define"] --> B{"¿Son datos o son archivos?"}
    B -->|"Datos"| C["extensions con clave de dominio inverso en plugin.json"]
    B -->|"Archivos"| D["Directorio de nivel superior con el nombre exacto del namespace"]
    B -->|"Campo raíz inventado"| E["Violación del esquema cerrado: el cliente lo reporta e ignora"]
    C --> F["Portable: los clientes ajenos lo ignoran sin validarlo"]
    D --> F
    E --> G["No aporta nada: ningún cliente puede asignarle semántica"]

5.1 La matriz de fatalidad, en una tabla

Situación en plugin.jsonConsecuencia
Campo de nivel superior desconocidoNo fatal: se reporta, se ignora y la carga continúa
extensions presente pero no es un objetoNo fatal: se reporta, se ignora y la carga continúa
Namespace de extensions que el cliente no implementaSe ignora sin validar su contenido
Campo requerido ausente, de tipo incorrecto o vacíoFatal: el plugin se rechaza; el cliente DEBERÍA decir cuál
Campo desconocido dentro de author, o valor no stringFatal: manifiesto inválido
$schema de versión no soportada ni reconocida como compatibleFatal: el plugin se rechaza; el cliente DEBERÍA reportar la versión
Cualquier otra violación del esquemaFatal: ningún componente se descubre ni se ejecuta

6. Versionado de tu plugin

6.1 Lo que dice la especificación

La sección 10.2 cabe en cuatro líneas. Los plugins DEBERÍAN (SHOULD) usar Versionado Semántico para version, con esta tabla:

SegmentoSignificadoDescripción
MajorCambio incompatibleCambio de comportamiento o de esquema incompatible.
MinorFuncionalidad retrocompatibleComportamiento nuevo sin romper clientes ni usuarios existentes.
PatchCorrección retrocompatibleCambio correctivo sin ruptura de comportamiento intencionada.

Y el cliente PUEDE (MAY) usar version para determinar si hay actualizaciones disponibles y si las cachés están obsoletas.

Eso es todo lo normativo. Fíjate en lo que no dice:

  • No obliga a incluir version; es un campo opcional de metadatos (§5.4).
  • No define formato validado por esquema: en plugin.schema.json, version es simplemente "type": "string", sin pattern.
  • Y §5.4 lo blinda por el otro lado: el cliente NO DEBE rechazar un manifiesto solo porque version no sea SemVer válido. La misma protección cubre a homepage, repository y author.url que no sean URLs reconocidas, a author.email que no sea un email reconocido, y a license que no sea SPDX.

version es, por tanto, una señal cooperativa, no un contrato ejecutado por el cliente: nadie te impedirá publicar version: "primavera-2", solo perderás la capacidad de que las herramientas razonen sobre tus actualizaciones.

6.2 Qué cuenta como cambio mayor en un plugin

La spec da la definición abstracta —“cambio de comportamiento o de esquema incompatible”— pero no la traduce a los componentes concretos de un plugin. Lo que sigue es una guía práctica, no texto normativo: esa tabla aplicada a la superficie observable de un plugin, que son sus nombres y contratos visibles.

CambioSegmento sugeridoPor qué
Renombrar o eliminar un directorio bajo skills/MajorEl skill deja de existir con ese nombre
Renombrar o eliminar una clave de mcpServersMajorEl identificador del servidor cambia para el cliente
Cambiar el type de un servidor de stdio a streamable-httpMajorCambia el modelo de despliegue, de confianza y de red
Cambiar el name del pluginMajorEs la identidad del paquete
Exigir una variable nueva en env que antes no hacía faltaMajorRompe instalaciones existentes
Subir la versión de Agent Plugins declarada en $schemaMajorLos clientes que solo soporten la anterior rechazarán el plugin
Añadir un skill nuevo bajo skills/MinorSuperficie nueva sin quitar nada
Añadir una entrada nueva a mcpServersMinorLos servidores existentes siguen igual
Añadir un namespace nuevo en extensionsMinorQuien no lo implementa lo ignora sin validarlo
Corregir un bug en un script bajo skills/x/scripts/PatchComportamiento previsto sin cambio de contrato
Cambiar description, homepage, keywords o authorPatchMetadatos que no afectan el comportamiento

El caso más subestimado es el sexto: subir la versión de spec declarada en $schema es un cambio mayor de tu plugin, aunque tu código no cambie ni una línea, porque un cliente que no reconoce el identificador nuevo DEBE rechazar el plugin entero. Es la ruptura más total posible.

6.3 Estrategia de evolución en el tiempo

flowchart TD
    A["Cambio propuesto en el plugin"] --> B{"¿Desaparece o se renombra algo que ya existía?"}
    B -- Si --> C["Major"]
    B -- No --> D{"¿Cambia el $schema de Agent Plugins?"}
    D -- Si --> C
    D -- No --> E{"¿Aparece superficie nueva?"}
    E -- Si --> F["Minor"]
    E -- No --> G["Patch"]
    C --> H["Publicar CHANGELOG con la ruta de migración"]
    F --> H
    G --> H

Reglas de higiene que se derivan del formato:

  • Mantén el name estable de por vida. Es la identidad del paquete y el esquema lo restringe con fuerza. Renombrar equivale a publicar un plugin distinto.
  • Usa PLUGIN_DATA para todo lo que deba sobrevivir a una actualización. La spec obliga al cliente a preservar ese directorio entre actualizaciones, mientras que PLUGIN_ROOT se reemplaza al actualizar el paquete. Dependencias, código generado, cachés y estado van a PLUGIN_DATA; scripts, binarios y configuración empaquetada se referencian desde PLUGIN_ROOT.
  • Añade antes de quitar. Para renombrar un skill, publica primero una versión menor con el nombre nuevo junto al viejo, y elimina el viejo en la mayor siguiente. Los skills se descubren por nombre de directorio inmediato, así que dos directorios conviven sin conflicto.
  • Cuando subas de versión de spec, sube ambos $schema a la vez. Si dejas mcp.json en la anterior, MCP se deshabilita entero mientras las skills siguen cargando: un fallo a medias que parece éxito.
  • Trata CHANGELOG.md como parte del paquete. El layout estándar de §4.2 lo muestra junto a LICENSE en la raíz. No es obligatorio, pero es el único lugar donde explicar una ruptura: la spec no define deprecación ni migración.
  • No dependas de nada que la spec no garantice. Un plugin conformante NO DEBE depender de una variable del entorno base que la spec no exija o que la configuración del servidor no suministre explícitamente, ni de que un PATH configurado afecte la resolución de un command desnudo.

Los catálogos reales suelen codificar la versión fuera del manifiesto: en el repositorio google/skills, cada entrada fija la versión en un campo ref que apunta a un tag de git y no publica version por plugin. Eso no es Agent Plugins: la especificación no define el concepto de catálogo ni de marketplace, y el término no aparece ni una vez en el documento. Es convención de producto, que vemos en el capítulo 9 y en el curso hermano de Google Skills.

Consecuencia práctica: el version de tu plugin.json y el tag que publiques son dos cosas que debes mantener sincronizadas.

7. Errores frecuentes

  • Creer que $schema se descarga. El cliente NO DEBE recuperar un esquema mientras carga un plugin. Es un selector de versión local.
  • Dejar mcp.json en otra versión que plugin.json. No rompe el plugin, pero deshabilita MCP entero: parece cargar bien y le faltan las herramientas.
  • Meter campos propios en la raíz del manifiesto. El esquema es cerrado: van bajo extensions, con clave de dominio inverso.
  • Suponer que un cliente conformante soporta skills y MCP. Basta con uno de los dos tipos de componente, y en MCP basta con stdio o streamable-http.
  • Tomar el apéndice A o FUTURE_CONSIDERATIONS.md como norma. Ambos son no normativos; ante conflicto manda el texto de la especificación.
  • Guardar estado dentro de PLUGIN_ROOT. Se pierde en la actualización siguiente. Ese es el problema que PLUGIN_DATA resuelve.

Resumen

  • Agent Plugins versiona el release completo: el texto normativo y los dos esquemas comparten versión, y cada release DEBE publicar ambos aunque uno no haya cambiado.
  • $schema declara la versión de spec del paquete y el cliente lo usa como selector local: NO DEBE descargarlo, y si no la reconoce, rechaza el plugin.
  • Si existe mcp.json, su $schema DEBE declarar la misma versión que plugin.json. El desajuste deshabilita MCP, pero no invalida los demás tipos de componente.
  • Los identificadores canónicos publicados NO DEBEN reasignarse, y un plugin PUEDE seguir apuntando a una versión anterior.
  • La conformidad obliga por igual a paquetes y a clientes: el cliente cumple ocho capacidades mínimas y puede soportar un solo tipo de componente.
  • Solo dos situaciones del manifiesto son no fatales —campo raíz desconocido y extensions no objeto—; cualquier otra violación rechaza el plugin entero.
  • Lo propietario va en extensions con clave de dominio inverso o en un directorio de nivel superior con ese mismo nombre; los clientes ajenos lo ignoran sin validarlo.
  • version es una señal cooperativa: DEBERÍA ser SemVer, y subir el $schema de spec es, para tu plugin, un cambio mayor.
  • 1.0.0 no define permisos, firmas, secretos, dependencias ni validador oficial.

Siguiente: Validar un plugin: JSON Schema y automatización