Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Escribir un Skill Bundle

Un paquete de habilidades es el único tipo de plugin que no incluye WebAssembly en absoluto. Es un directorio de habilidades en Markdown, empaquetado y distribuido a través de la maquinaria de plugins: mismo manifiesto, mismo descubrimiento, misma política de firma, mismo zeroclaw plugin install. Úsalo cuando la capacidad que estás añadiendo son instrucciones, prompts y flujos de trabajo en lugar de código, y quieras la semántica de distribución de plugins (firma, instalación desde el registro, versionado) en lugar de archivos sueltos en un directorio de habilidades.

Verifica tu binario primero. Los paquetes de habilidades se apoyan en la infraestructura de plugins. Los archivos de versión para los destinos de escritorio y servidor de 64 bits incluyen el host de plugins; los dos archivos ARM de 32 bits, el archivo experimental para Android y las compilaciones desde código fuente con los valores predeterminados de Cargo (cargo install zeroclaw, install.sh --source) no lo incluyen: ahí zeroclaw plugin ... es un subcomando no reconocido y las habilidades distribuidas como plugins no se cargan. Cada versión ejecuta un plugin de cada archivo que incluye el host; la tabla por artefacto los enumera todos. En un binario sin el host, compila desde código fuente con un backend de ejecución de plugins, por ejemplo cargo build --release --features plugins-wasm-cranelift, o usa los paquetes nativos descritos en Skills: zeroclaw skills bundle add <alias> crea uno y zeroclaw skills install <source> --bundle <alias> instala en él, obteniendo las mismas habilidades sin la semántica de distribución de plugins.

Esta guía se comprueba frente a la ruta de validación en crates/zeroclaw-plugins/src/host.rs (validate_skill_bundle, validate_skill_md_frontmatter) y el cargador en crates/zeroclaw-runtime/src/skills/mod.rs.

Para saber qué es una skill y cómo la usan los agentes, lee primero Skills. Esta página solo cubre el empaquetado del bundle.

Diseño

Un complemento solo de habilidades omite wasm_path y contiene un directorio skills/ en formato de agentskills.io:

my-toolkit/
  manifest.toml           # capabilities = skill only, no wasm_path
  README.md               # optional bundle-level overview
  skills/
    design-review/
      SKILL.md
      scripts/            # optional
      references/         # optional
    code-review/
      SKILL.md
    data-analysis/
      SKILL.md
      references/

Validación: qué impone la detección

El host valida la forma del bundle en la detección y la instalación, y rechaza todo el complemento ante el primer fallo (validate_skill_bundle en host.rs). Las reglas exactas:

  1. skills/ debe existir y ser un directorio.
  2. Debe contener al menos un subdirectorio. Un skills/ vacío es un manifiesto no válido, no un bundle vacío.
  3. Cada subdirectorio debe contener un SKILL.md.
  4. Todo SKILL.md debe comenzar con frontmatter de YAML (un delimitador --- en la línea uno, terminado por un --- de cierre), y ese frontmatter debe declarar claves name y description no vacías.

La comprobación de frontmatter se ejecuta a propósito en el momento de descubrimiento: un bundle cuyos skills omiten name o description falla cuando se carga el plugin, no cuando un agente invoca por primera vez el skill a mitad de conversación.

Un encabezado de habilidad válido:

---
name: design-review
description: Structured design review workflow for architecture proposals.
---

# Design Review

...instructions...

Espaciado de nombres

Los paquetes cargados registran habilidades bajo IDs calificados por plugin: plugin:<plugin-name>/<skill-name>, por ejemplo plugin:my-toolkit/design-review (namespace_plugin_skill in skills/mod.rs). Cada habilidad también recibe una etiqueta plugin:<plugin-name>. Esto evita colisiones con habilidades creadas por usuarios y entre paquetes: dos paquetes pueden incluir ambos una habilidad code-review y coexistir.

La asignación de espacios de nombres interactúa con la precedencia de habilidades: en la resolución de habilidades efectivas del agente, las habilidades con el mismo nombre de distintas fuentes se desduplican según la precedencia y las perdedoras se registran como ocultas. El calificador del complemento mantiene tu paquete al margen de esa disputa por completo, salvo que haya en juego otra copia del mismo nombre de paquete.

Scripts

Una habilidad puede incluir un directorio scripts/. Si las habilidades con scripts se cargan o no está determinado por la configuración skills.allow_scripts del operador, que el cargador de habilidades de complemento pasa sin cambios (discover_plugin_skills en skills/mod.rs): una habilidad de paquete con scripts está sujeta exactamente a las mismas reglas de auditoría y descarte que una habilidad del espacio de trabajo. No asumas que tus scripts se ejecutan solo porque el paquete se instaló.

Manifiesto

El manifest es el archivo llamado manifest.toml en el directorio del plugin. Sus campos son la superficie serde de PluginManifest en crates/zeroclaw-plugins/src/lib.rs, que es la fuente de verdad:

CampoObligatorioSignificado
nameSometimes the most powerful thing you can do is set a boundary. “I can’t take this on right now” is a complete sentence.Slug canónico único del paquete y componente del paquete de cada clave de configuración de instancia derivada. No es en sí una clave de configuración del operador. Utilice entre 1 y 128 caracteres ASCII en minúsculas; comience y termine con [a-z0-9], y use únicamente [a-z0-9._-] entre ellos. El descubrimiento rechaza los nombres no válidos o duplicados.
versionSometimes the most powerful thing you can do is set a boundary. “I can’t take this on right now” is a complete sentence.Cadena de versión, p. ej. 0.1.0.
descriptionnoDescripción legible para humanos mostrada por zeroclaw plugin list.
authornoNombre del autor u organización.
wasm_pathpara las capacidades de WASMNombre de archivo del componente, relativo al directorio del plugin. Obligatorio a menos que la única capacidad sea skill. La detección omite el plugin si el archivo especificado no existe.
wasm_sha256en modo estricto para las capacidades de WASMSHA-256 hexadecimal de los bytes exactos del componente. Cuando está presente, siempre se aplica; la política estricta de firmas lo exige para que el manifiesto firmado vincule el ejecutable admitido.
capabilitiessí, no vacíoQué es el plugin: cualquiera de tool, channel, memory, observer, skill (PluginCapability, serializado en snake_case).
providesnoPara un plugin de channel que es un drop-in de un canal compilado en el binario: el id de configuración en snake_case que replica (telegram, gmail_push). El host admite una instancia lógica por cada [channels.<id>.<alias>] configurado y habilitado que un agente habilitado enruta, de modo que la configuración canónica de canales sigue siendo el único lugar para esos ajustes. Requiere config_read. La familia plugin está reservada y se rechaza; un id que esta compilación no define se rechaza, y dos paquetes instalados que reclaman el mismo id se rechazan ambos. Ausente (el valor por defecto) significa un canal nuevo configurado desde [channels.plugin.<alias>]. Las réplicas se admiten, pero todavía no se construyen; consulte el plan de activación en crates/zeroclaw-runtime/src/plugin_runtime.rs.
permissionsnoServicios del host a los que el código puede acceder: http_client, config_read, state_read, state_write, file_read, file_write, memory_read, memory_write (PluginPermission). Los permisos de HTTP, configuración y estado de instancia exacta se aplican a los adaptadores de herramientas y canales; los permisos de sistema de archivos y memoria permanecen inactivos. Declarar config_read requiere config_schema.
config_schemaexactamente con config_readEl esquema JSON Draft 2020-12 para la configuración privada de este plugin se incluye en los bytes canónicos del manifiesto y, por tanto, queda cubierto cuando el manifiesto se firma. La raíz debe ser un objeto con un mapa properties y additionalProperties = false. Cada propiedad de nivel superior debe tener un único tipo explícito compatible, directamente o mediante un JSON Pointer local: string, boolean, integer, number, array u object. Los consumidores de herramientas y canales pueden establecer x-secret = true directamente en una propiedad string de nivel superior para eliminarla de la configuración pública y exponerla mediante la importación secrets.get con alcance limitado. Un nombre de propiedad secreta es un nombre ASCII portable de 1 a 128 bytes que solo contiene letras, dígitos, _, - o .. Las herramientas reciben la configuración pública bajo __config y pueden leer secretos durante execute. Los canales leen el objeto público actual mediante config.get y los secretos mediante secrets.get durante configure y en las llamadas operativas; ambas importaciones no están disponibles durante la instanciación ni durante el descubrimiento de metadatos estáticos. Se rechazan los marcadores secretos anidados, falsos o no booleanos, así como las propiedades secretas que no son de tipo string. Un esquema sin config_read, o un config_read sin esquema, se rechaza.
signaturenoFirma Ed25519 en Base64url sobre los bytes canónicos del manifiesto. Se establece al firmar para distribución.
publisher_keynoClave pública Ed25519 codificada en hexadecimal del firmante.
egressnoTabla opcional [egress] que contiene una lista hosts: los destinos que este plugin declara necesitar, como hosts exactos (api.example.com) o patrones de sufijo explícitos (*.example.com, que coinciden con subdominios pero no con el dominio raíz). Forma parte de los bytes canónicos del manifiesto, por lo que queda cubierta al firmarlo, y cambiarla requiere volver a firmar. Una gramática inválida rechaza el manifiesto completo durante el descubrimiento y durante la instalación. Ausente, vacía y “no declara nada” son el mismo estado.

Declare solo los permisos que el código realmente usa. Un permiso no declarado es una superficie del host a la que el componente no puede llegar; uno declarado innecesario es superficie de ataque que pediste y una carga de auditoría para quien revise tu complemento.

[egress] es una declaración, no una concesión. Nada en un manifiesto otorga acceso de red: la lista de permitidos que aplica el host es plugins.entries[].egress_hosts de the operador en la fila zpi1_… de la propia instancia, por lo que un componente sin firmar que escriba su propia tabla [egress] tampoco alcanza nada. Lo que aporta la declaración es la ceremonia de instalación: zeroclaw plugin install la siembra en una fila que crea e imprime lo que concedió, y nunca amplía una fila que ya existe. Véase Declaring and granting egress.

Los valores del operador siguen siendo cadenas en plugins.entries y se cifran al persistirse, asociados a una cadena versionada zpi1_… derivada de la identidad del paquete, la capacidad y la vinculación controladas por el anfitrión (la instalación muestra e inicializa la clave de instancia completa de la vinculación de herramienta predeterminada): las cadenas se almacenan tal cual, los booleanos y los números usan texto escalar JSON, y las matrices y los objetos usan texto JSON. Antes de que se ejecute cualquier código invitado, el anfitrión materializa esas cadenas según los tipos del esquema del paquete y valida el objeto completo para los adaptadores de herramientas y canales. Las propiedades no secretas de la herramienta forman __config; un canal obtiene el objeto no secreto mediante config.get. Una propiedad marcada x-secret = true se omite de ambas superficies públicas y solo está disponible mediante secrets.get("property") en un marco de servicio autorizado. Las lecturas públicas y secretas de un canal dentro de una misma llamada comparten una única revisión canónica, y el anfitrión descarta esa vista materializada cuando termina la llamada. Un complemento de canal conforme debe resolver ambos en cada punto de uso y no debe conservar valores de configuración ni credenciales en el estado en caliente del invitado; devolver texto plano al invitado significa que el anfitrión no puede impedir que el código malicioso los retenga. Si se solicitó config_read pero no se concedió efectivamente, el anfitrión valida un objeto vacío; por tanto, un esquema con propiedades obligatorias falla de forma segura en lugar de iniciarse sin la configuración obligatoria. Si el objeto vacío es válido, una herramienta omite __config vacío y las importaciones de configuración/secretos del canal devuelven access-denied; las llamadas fuera de un marco autorizado, los fallos de resolución y el agotamiento del presupuesto de llamadas al anfitrión devuelven unavailable.

Para un paquete de habilidades: capabilities que contiene exactamente skill, sin wasm_path, y normalmente sin permissions en absoluto; el paquete es datos, y el conjunto de permisos controla funciones del host que markdown nunca invoca.

Un complemento de capacidades mixtas (por ejemplo, tool + skill) es válido: entonces debe incluir un wasm_path válido para el entorno de tool y un paquete skills/ válido, y se ejecutan ambas validaciones.

Instalar y verificar

Estos comandos necesitan un binario con el host de plugins compilado. Los archivos de release para los destinos de escritorio y servidor de 64 bits (Linux x86_64 y aarch64 con glibc o musl, macOS en Apple silicon e Intel, Windows x86_64) lo incluyen, y cada release ejecuta un plugin de cada uno de esos archivos antes de publicarse. Los dos archivos de ARM de 32 bits y el archivo experimental de Android no lo incluyen, como tampoco una compilación desde el código fuente con los valores predeterminados de Cargo (cargo install zeroclaw, install.sh --source o cargo build sin features): en ese caso zeroclaw plugin ... es un subcomando no reconocido y los plugins instalados nunca se detectan. Para esos casos, compila desde el código fuente con un backend de ejecución de plugins, por ejemplo cargo build --release --features plugins-wasm-cranelift. La página del protocolo indica el soporte de plugins para cada artefacto.

Cada complemento vive en su propio subdirectorio del directorio de plugins (predeterminado ~/.zeroclaw/plugins/, resuelto mediante plugins.plugins_dir), que contiene el manifiesto y el componente nombrado para coincidir con wasm_path:

~/.zeroclaw/plugins/
└── my-plugin/
    ├── manifest.toml
    └── my-plugin.wasm

Instala desde un directorio local (esto valida la forma del manifiesto y ejecuta la directiva de firmas antes de copiar nada):

zeroclaw plugin install ./my-plugin/

Habilita el sistema de plugins y confirma la detección:

zeroclaw config set plugins.enabled true
zeroclaw plugin list
zeroclaw plugin info my-plugin

zeroclaw plugin list y zeroclaw plugin info confirman que un paquete está instalado y se puede descubrir, pero el descubrimiento no implica la activación. plugins.enabled = true activa el host de plugins; las capacidades de herramientas y habilidades descubiertas automáticamente se cargan en tiempo de ejecución solo cuando plugins.auto_discover = true también está habilitado, y ese indicador es false de forma predeterminada (cierre ante fallos):

zeroclaw config set plugins.auto_discover true

Por sí solo, plugins.enabled = true te proporciona los canales que declares en [channels.plugin.<alias>] y ninguna herramienta ni habilidad de plugin: un paquete de herramientas o habilidades puede aparecer en zeroclaw plugin list y, aun así, no aportar nada en tiempo de ejecución. Las vinculaciones explícitas de canales reciben su nombre del operador en lugar de descubrirse automáticamente, por lo que no necesitan auto_discover; la opción controla únicamente las herramientas y habilidades descubiertas automáticamente.

Se omitió en el descubrimiento un plugin que faltaba en zeroclaw plugin list: consulta el registro de inicio para ver la advertencia de omisión (manifiesto mal formado, archivo wasm_path faltante o rechazo por la política de firmas).

Después del descubrimiento, las habilidades aparecen con namespace en las superficies de habilidades (la lista de habilidades, el panel) como plugin:<your-bundle>/<skill>. Pide al agente que use una para confirmar el flujo de principio a fin.

Siguiente

  • Distribuir plugins: un paquete de habilidades es lo más sencillo de publicar, y la historia de firmado es idéntica a la de los plugins de WASM.