Cómo funcionan los complementos
Esta página explica el sistema de plugins desde el punto de vista de un operador: cómo se descubre un plugin, qué se le अनुमति hacer y cómo el host mantiene contenido a un plugin no confiable. Para el contrato en disco que implementa el autor de un plugin (campos del manifiesto, exportaciones del puente, funciones del host), consulta Protocolo de plugin.
La forma del sistema
Un plugin es un módulo de WebAssembly aislado más un manifiesto. El host lo carga, lee las capacidades y permisos que declara, y expone sus herramientas al agente solo cuando el operador ha activado el sistema de plugins. Nada de un plugin es implícito: un plugin obtiene exactamente las capacidades que su manifiesto declara y la política del operador permite, y nada más. Para crear uno tú mismo, empieza con las guías de plugins.
Tres propiedades se mantienen en cada capa:
- Deshabilitado de forma predeterminada. El sistema de complementos no carga nada a menos que
[plugins] enabled = true. Una compilación predeterminada sin configuración de complementos no ejecuta ningún código de complementos. - Denegar por defecto. Un plugin accede a una capacidad del host (egreso HTTP, configuración, memoria) solo al declarar el permiso correspondiente en su manifiesto. Una capacidad no declarada es inaccesible, no simplemente no utilizada.
- Verificado por política. Si un plugin sin firmar o no confiable se carga o no, es decisión del operador, establecida una vez en la configuración y aplicada de forma uniforme en el descubrimiento.
Ciclo de vida de la carga de un complemento
Cuando el runtime construye su conjunto de herramientas, el cargador de plugins pasa por estas etapas en orden. Un plugin que falla en una etapa anterior nunca llega a una posterior.
- Gate. Si
[plugins] enabledes false, el cargador no hace nada. Este es la primera y más barata comprobación. - Descubrir. El cargador escanea el directorio de plugins resuelto (
[plugins] plugins_dir, por defecto~/.zeroclaw/plugins/) en busca de subdirectorios que contengan unmanifest.toml. Omite los directorios con prefijo de punto, incluido el directorio de preparación oculto en el quezeroclaw plugin installconstruye un paquete antes de renombrarlo a su ubicación definitiva, de modo que una instalación incompleta nunca se carga. - Validar la estructura. Cada manifiesto debe declarar al menos una capacidad, y un plugin que no sea una skill debe indicar un
wasm_pathrelativo y confinado. Las rutas con recorrido de directorios y los enlaces simbólicos se rechazan. Un manifiesto mal formado se omite con una advertencia y nunca se carga. - Aplicar la política de firmas. Cada plugin se comprueba frente a
[plugins.security] signature_modeytrusted_publisher_keysconfigurados. Un plugin que no supera la política se descarta del conjunto cargado y no se expone como una herramienta. - Admitir bytes ejecutables. El host abre el componente confinado una sola vez, verifica cualquier
wasm_sha256declarado y conserva esos bytes exactos. En el modostrict, el manifiesto firmado debe declarar este resumen. Los adaptadores compilan el búfer admitido en lugar de volver a abrir su ruta. En Unix, el host abre el directorio del paquete una sola vez y accede al componente desde ese descriptor, un componente de ruta a la vez, sin seguir nunca un enlace simbólico; así, mover o reemplazar un directorio durante la admisión hace que la admisión falle o deja la lectura dentro del paquete que fue confinado. El componente debe ser un archivo regular, y un FIFO o un dispositivo falla de inmediato en lugar de bloquearse. El directorio del paquete y el manifiesto todavía se localizan por ruta de archivo cuando comienza la admisión; en el modostrict, elwasm_sha256firmado es lo que vincula el manifiesto a los bytes. Las demás plataformas mantienen las comprobaciones por ruta, que rechazan un reemplazo que siga presente cuando se ejecutan, pero no hacen atómica la búsqueda ni impiden que un FIFO bloquee la apertura. - Registrar herramientas. Los plugins de herramientas que sobreviven al filtrado se envuelven como herramientas del agente y se añaden después de las integradas. Un plugin cuyo nombre de paquete o nombre de herramienta entre en conflicto con una herramienta ya registrada se rechaza con una advertencia en lugar de registrarse; consulte Conflictos de nombres de herramientas. Los plugins de herramientas y de habilidades se descubren automáticamente, por lo que esta enumeración solo ocurre cuando
[plugins] auto_discover = true(valor por defectofalse, cierre por fallo): conenabled = trueperoauto_discover = false, no se carga ninguna herramienta ni habilidad de plugins, aunque los canales que declare en[channels.plugin.<alias>], ya sea a mano o conzeroclaw plugin bind, siguen activándose. El cargador de habilidades aplica la misma restricción deauto_discover.
La etapa de firma es la que se configura con mayor facilidad de forma incorrecta, por lo que vale la pena entenderla por sí sola.
Recuperación de instalaciones heredadas
Ejecute zeroclaw plugin migrate para reubicar los directorios de paquetes heredados en [plugins] plugins_dir. La recuperación automática busca en plugins/ de la raíz de datos configurada, en <install>/workspace/plugins sin dividir y en el destino <install>/data/plugins del productor V2 real, aunque el campo data sea distinto. Las nuevas divisiones del sistema de archivos V2 mueven los plugins a los datos del host, de modo que las divisiones nuevas y las reanudadas sigan siendo accesibles sin usar el espacio de trabajo activo y escribible del agente predeterminado como fuente de recuperación. Los datos del host no son necesariamente el directorio de plugins de runtime configurado; plugin migrate realiza esa reubicación posterior. Se excluyen el destino configurado y los alias canónicos de este, y los directorios raíz duplicados se informan una sola vez.
Se siguen los alias compatibles de estas raíces heredadas. Se excluyen los alias del destino canónico y se deduplican los alias de la misma raíz. Se excluye una raíz que se superponga con un espacio de trabajo de agente conocido, ya sea que esté dentro de ese espacio de trabajo o que lo contenga, incluidos sus alias. Los roles conocidos provienen de la ruta real del espacio de trabajo de cada agente configurado, del valor predeterminado implícito y del espacio de trabajo predeterminado histórico. Las rutas existentes se comparan de forma canónica; los espacios de trabajo declarados que no existen se comparan de forma conservadora como rutas léxicas normalizadas, resolviendo un alias de ancestro existente cuando esté disponible. La selección no crea un espacio de trabajo faltante ni trata la ruta declarada como evidencia de una migración antigua.
Esta es la selección de raíz: el mover existente todavía vuelve a escanear una raíz elegible con sus propias comprobaciones de paquetes. Tanto la pista de recuperación como el mover exigen un directorio de paquete hijo ordinario, igual que el descubrimiento en tiempo de ejecución. Los enlaces simbólicos a directorios hijos permanecen en el origen; no se mueven ni se materializan, incluso en una raíz con paquetes ordinarios. Un alias de manifiesto dentro de un directorio de paquete ordinario sigue usando las comprobaciones existentes de carga y admisión del manifiesto.
Esto no crea una garantía global de no seguir enlaces simbólicos, una instantánea autenticada ni un nuevo contrato concurrente de no sobrescritura. Su comprobación existente de destino con el mismo nombre deja los paquetes en conflicto en el origen para que el operador los resuelva y vuelva a intentarlo.
El asistente de migración de directorios no edita la configuración de plugins, los permisos concedidos, la confianza en el editor ni la habilitación. La carga de la configuración previa al comando conserva sus efectos normales de inicialización y migración. Mover los paquetes los hace elegibles para el descubrimiento normal: los plugins de herramientas y de skills pueden quedar disponibles cuando los plugins estén habilitados y auto_discover = true, sujeto a la admisión. La reubicación en sí no verifica la compatibilidad ABI ni autentica el origen.
Paquetes ya divididos en un espacio de trabajo del agente
Las versiones anteriores podían mover paquetes a <install>/agents/default/workspace/plugins. Esa ubicación histórica y un espacio de trabajo de agente activo personalizado ya no son orígenes automáticos para plugin migrate. Un manifiesto, un nombre de copia de seguridad coincidente o un marcador escrito por el llamador no autorizan la adopción de todo el directorio. Inspeccione cada paquete que pretenda adoptar y, a continuación, seleccione su directorio individual con el comando de instalación existente:
zeroclaw --config-dir '/operator/install' plugin install \
'/operator/install/agents/default/workspace/plugins/package-name'
Usa las rutas reales de tu instalación y de tus paquetes; no pases el directorio plugins/ completo. De igual modo, un paquete ubicado en una copia de seguridad puede seleccionarse explícitamente mediante su ruta real. La autoridad la otorga la acción de instalación del operador, no el historial aparente de la ruta. Esto requiere una compilación con soporte de CLI para plugins.
Esta es una instalación nueva de un paquete compatible. El host aplica las reglas vigentes de manifiesto, firma, payload y esquema de configuración, y la CLI verifica por defecto la carga de los paquetes ejecutables frente a su ABI WIT y sus límites. Con la política estricta, es posible que se rechacen los paquetes no firmados o no confiables, los manifiestos antiguos incompletos, los componentes incompatibles o las filas de configuración de formato legado no soportadas. Antes de volver a intentarlo, siga el diagnóstico y la guía de migración a configuración tipada. No se proporciona conversión de formatos históricos ni omisión de la política de firma. Los paquetes instalados con el mismo nombre se rechazan en lugar de reemplazarse silenciosamente.
La instalación explícita conserva el directorio de origen. Escribe el manifiesto admitido y la carga útil ejecutable, y copia el contenido declarado de las skills. Los archivos auxiliares arbitrarios no constituyen un contrato de recuperación de directorio completo, y la copia de skills no es una instantánea inmutable de generación. Para los enlaces de herramientas que requieren estado propiedad del host, la instalación puede crear filas de configuración tipadas que falten e inicializar los destinos de salida HTTP declarados en las filas nuevas. Las filas y los permisos existentes no se amplían automáticamente, y las filas antiguas con nombre de paquete no se convierten silenciosamente. Revise estos efectos de la instalación y configure los valores requeridos antes de habilitar el uso en tiempo de ejecución. Por lo tanto, la adopción explícita es independiente del comportamiento de configuración y permisos sin cambios del asistente de migración automática.
Política de firma
Cada manifiesto de plugin puede llevar una firma Ed25519 y la clave pública codificada en hexadecimal del publicador que lo firmó. El operador decide con qué rigor se aplica esa firma mediante [plugins.security] signature_mode:
| Modo | Qué carga | Usar cuando |
|---|---|---|
disabled | Todo plugin bien formado, firmado o no | Desarrollo local con plugins que has creado tú mismo |
permissive | Todo plugin bien formado; las firmas no firmadas, no confiables e inválidas se cargan con una advertencia | Migración hacia la firma sin romper las instalaciones existentes |
strict | Solo los complementos con una firma válida de un editor de confianza se cargan | ¿Algún host compartido o de producción? |
En el modo strict, el publisher_key del manifiesto debe aparecer en [plugins.security] trusted_publisher_keys, y la firma debe verificarse contra los bytes canónicos del manifiesto. Los plugins ejecutables también deben declarar un wasm_sha256 firmado que coincida con los bytes exactos admitidos. Un plugin que no supere cualquiera de estas comprobaciones se descarta durante el descubrimiento y nunca se convierte en una herramienta. El valor predeterminado es disabled, para que una copia local recién clonada funcione sin gestión de claves, pero un host que cargue plugins desde cualquier origen que no controle debería ejecutarse en modo strict.
Esta política se aplica de forma uniforme: la misma comprobación que realiza el host cuando enumeras los plugins es la comprobación que el runtime del agente aplica cuando construye el conjunto de herramientas, así que un plugin que no puedes ver en modo strict también es un plugin que el agente no puede invocar.
Conflictos de nombres de herramientas
El registro rechaza un conflicto de nombres en lugar de permitir que una herramienta oculte a otra. Los plugins de herramientas se registran en orden de nombre de paquete, y el host verifica cada uno dos veces:
- Nombre del paquete. Un plugin cuyo nombre de paquete (el
namedel manifiesto) coincide con una herramienta ya registrada se rechaza antes de instanciar su componente. El host registra un eventoWARNconerror_keyplugin_package_name_conflicten susattributes. - Nombre de la herramienta. El huésped declara su propio nombre de herramienta, por lo que el host solo lo conoce al instanciar el componente para leer sus metadatos. Un plugin cuyo nombre de herramienta coincide con una herramienta ya registrada no se registra. El host registra un evento
WARNconerror_keyplugin_tool_name_conflicten susattributes. Un nombre de herramienta que contiene__se rechaza incluso cuando todavía no lo ocupa nadie, porque las herramientas MCP se nombran<server>__<tool>y se registran después de las herramientas de plugins. Ese rechazo llevaerror_keyplugin_tool_name_reserved.
Los nombres verificados son las herramientas que la compilación del registro ya ha registrado, incluidas las herramientas de plugins aceptadas antes en la misma pasada, más execute_pipeline cuando [pipeline] enabled = true. No es una lista fija de todos los nombres integrados: un integrado que una compilación no registra, por ejemplo porque su sección de configuración está deshabilitada, no está reservado en esa compilación. Salvo por el espacio de nombres MCP, las herramientas que se incorporan al registro después del registro de plugins quedan fuera de esta verificación. Asigne a los paquetes y herramientas de plugins nombres que sean únicos por sí mismos, en lugar de depender de esta verificación.
Capacidades y permisos
Un manifest declara dos cosas separadas, y la distinción importa.
- Las capacidades son el tipo de extensión que es el plugin:
tool,channel,memory,observeroskill. Un plugintoolaporta herramientas que el LLM puede invocar. - Permisos son los servicios del host a los que el código del plugin puede acceder en tiempo de ejecución: salida HTTP, configuración, memoria. Un permiso que el manifiesto no declara es una función del host a la que el plugin no puede acceder.
El host concede permisos de forma restringida: un permiso que el manifiesto no declara corresponde a una función del host a la que el complemento no puede acceder. La configuración se resuelve a partir de una identidad de instancia emitida por el host, por lo que un complemento no puede seleccionar otro paquete o enlace y nunca lee el entorno sin procesar del proceso. http_client controla la superficie saliente de wasi:http; la política compartida de salida protegida contra SSRF sigue siendo trabajo complementario de refuerzo de complementos. Esta página cubre el límite de la política de firmas.
Referencia de configuración
Todas las configuraciones residen bajo las rutas de configuración plugins.* y se establecen a través de cualquier superficie de configuración (zerocode, el gateway o la CLI):
# Interruptor maestro. Nada se carga mientras esto sea falso.
zeroclaw config set plugins.enabled true
# Cargar complementos de herramientas y habilidades detectados automáticamente durante la ejecución (predeterminado: false).
# Without this, `enabled = true` activates only explicitly-declared channels.
zeroclaw config set plugins.auto_discover true
# Dónde se descubren los plugins (predeterminado: ~/.zeroclaw/plugins).
zeroclaw config set plugins.plugins_dir ~/.zeroclaw/plugins
# deshabilitado | permisivo | estricto
zeroclaw config set plugins.security.signature_mode strict
Claves públicas Ed25519 codificadas en hexadecimal permitidas para publicar plugins en modo estricto.
zeroclaw config set plugins.security.trusted_publisher_keys '["a1b2c3d4e5f6..."]'
Un host destinado a cargar plugins de terceros debe establecer enabled = true, signature_mode = "strict" y enumerar únicamente las claves de los editores en los que confíes. Para cargar también plugins de herramientas y habilidades detectados automáticamente, establece además auto_discover = true; su valor predeterminado es false, por lo que enabled = true por sí solo activa únicamente los canales que declares en [channels.plugin.<alias>] y no las herramientas ni habilidades de los plugins. Un host que ejecute únicamente los plugins que construyas tú mismo puede dejar signature_mode con su valor predeterminado disabled durante el desarrollo y endurecerlo antes de compartir el host.
Una vinculación de canal se encuentra fuera de plugins.*, bajo [channels.plugin.<alias>]. Puedes escribir esa tabla a mano o dejar que zeroclaw plugin bind <package> --channel-alias <alias> la escriba para un paquete de canal instalado. El comando también inicializa la fila [[plugins.entries]] de la instancia, exige una marca explícita --egress declared o --egress none antes de crear esa fila a partir de un manifiesto que declara destinos y dispone de un transporte capaz de alcanzarlos (http_client, websocket_client o socket_client), e informa de lo que la instancia aún necesita antes de poder iniciarse. Nunca establece plugins.enabled y nunca modifica los channels de un agente. Consulta Vinculación de una instancia de canal.
Ejecutar plugins desde un binario de versión
El sistema de plugins es experimental: el contrato wit/v0 es inestable, por lo que un plugin debe compilarse con el WIT incluido en la versión que lo ejecuta, y una incompatibilidad aparece en la comprobación de carga durante la instalación y no en el manifiesto. Dentro de ese límite, los archivos de publicación para los destinos de escritorio y servidor de 64 bits incluyen el host de plugins y el compilador que carga los componentes .wasm, y cada publicación ejecuta un plugin de cada uno de esos archivos antes de publicarse. Los archivos ARM de 32 bits, el archivo experimental de Android y las compilaciones desde el código fuente con los valores predeterminados de Cargo no incluyen el host de plugins; la página del protocolo enumera todos los artefactos. Ejecutar un plugin en un binario de publicación requiere cuatro decisiones del operador, cada una desactivada por defecto:
- Instala el paquete.
zeroclaw plugin install <directory>para un paquete local, ozeroclaw plugin install <name>para uno del registro de plugins. La instalación valida el manifiesto, aplica la política de firmas, comprueba el digest del payload cuando el manifiesto lo declara e instancia el componente frente al WIT de este host (se omite con--no-verify). Un paquete que falle cualquiera de estas comprobaciones no se instala. La instalación (salvo con--no-verify),zeroclaw plugin info <name>yzeroclaw plugin list --verifycompilan e instancian el componente tanto si el sistema de plugins está habilitado como si no. La instanciación no llama a ninguna de sus exportaciones, pero sí ejecuta la función de inicio (start) que contengan los módulos core del componente, en un store sin acceso a archivos ni a la red, y con los límites de fuel, memoria y tiempo por llamada. - Activa el sistema de plugins.
zeroclaw config set plugins.enabled true, y luegozeroclaw config set plugins.auto_discover truepara que los plugins de herramientas y habilidades sean enumerados. Un paquete de herramienta o habilidad instalado no aporta nada hasta que se configuren ambos. Una vez configurados, cada compilación del registro de herramientas compila e instancia cada componente de herramienta admitido y le solicita su nombre, descripción y esquema de parámetros; se trata de código invitado que se ejecuta con los permisos y la política de salida declarados por el paquete, antes de cualquier aprobación, y a continuación la herramienta se ofrece al modelo. Un paquete de canal necesitaplugins.enabled, una declaración[channels.plugin.<alias>]y un agente habilitado que incluyaplugin.<alias>entre sus canales;auto_discoverno interviene en ello. Para un paquete que replica un canal nativo medianteprovides, la activación bajo[channels.<provides>.<alias>]queda registrada pero aún no se construye; el mismo paquete vinculado bajo[channels.plugin.<alias>]sí se ejecuta. - Aprueba cada llamada a herramienta. Una llamada a una herramienta de plugin necesita aprobación del operador como cualquier otra herramienta que no esté preaprobada: la CLI muestra una solicitud en la terminal y los canales envían su tarjeta de aprobación. Para permitir que un agente llame a una herramienta de plugin sin supervisión, añade la herramienta a la lista
auto_approvedel perfil de riesgo de ese agente, por ejemplozeroclaw config set risk_profiles.default.auto_approve '["<tool-name>"]'.config setreemplaza la lista completa: los valores predeterminados integrados se vuelven a combinar enrisk_profiles.defaultal cargar la configuración, pero cualquier entrada que hayas añadido tú debe repetirse, y un perfil con otro nombre conserva solo lo que pases.level = "full"y el comodín*preaprueban toda herramienta que no esté enalways_ask, y una respuesta Siempre preaprueba la herramienta para el resto de la sesión de CLI o del turno del canal, salvo las herramientas enalways_ask, que siempre vuelven a solicitar aprobación. Sin un aprobador, la llamada se deniega y no se ejecuta. - Elige una política de firma.
signature_modese mantiene endisabledde forma predeterminada, para que un plugin que hayas creado tú mismo se instale sin gestión de claves. En modostrict, solo se cargan los paquetes firmados con una clave incluida entrusted_publisher_keys; y como el registro oficial publica actualmente paquetes sin firmar, ninguno se instala en modostricthasta que sus editores los firmen.
Compilar un componente necesita memoria que pasa a ser ejecutable después de escribirse. Un host que prohíbe eso, como una unidad de systemd con MemoryDenyWriteExecute=yes (el valor predeterminado del módulo de Nix), rechaza toda carga de plugins porque el compilador no puede mapear código como ejecutable; el resto del demonio no necesita esos mapeos y sigue funcionando.
Para revertir, elimina el paquete con zeroclaw plugin remove <name>, o define plugins.enabled = false para dejar de cargar cualquier plugin sin desinstalarlo. Para volver a una versión sin el host de plugins, fija el binario con zeroclaw update --version <previous> --force; sin --force, el actualizador se niega a cambiar a una versión anterior. El actualizador resuelve los hosts Linux musl hacia el archivo glibc, así que una instalación musl, como la que proviene de un gestor de paquetes, se revierte reinstalando el archivo o paquete anterior.
Lo que un plugin todavía no puede hacer
Incluso con todos los permisos concedidos, el sandbox delimita un plugin:
- Se ejecuta como un módulo WebAssembly sin acceso implícito al proceso anfitrión ni al sistema de archivos fuera de su espacio de trabajo raíz. La salida de red está controlada por el permiso HTTP; el propio límite de salida protegido contra SSRF se entrega mediante el trabajo complementario de hardening de plugins.
- Una herramienta de confianza o un complemento de canal puede leer el texto sin formato de un secreto designado por el esquema mediante su importación
secrets.getcon ámbito restringido durante una llamada de servicio autorizada. Las herramientas obtienen acceso duranteexecute. Los canales reciben acceso aconfig.getysecrets.getduranteconfigurey las llamadas operativas; las lecturas realizadas dentro de una misma llamada usan una única revisión canónica, por lo que una rotación de los valores público y secreto de una misma vinculación estará disponible en la siguiente operación. La instanciación y el descubrimiento de metadatos estáticos no pueden usar ninguna de las dos importaciones. El host impide la inyección de configuración pública y la selección entre instancias, pero una importación que devuelve texto sin formato no puede impedir que un invitado malicioso conserve lo que lee. Los complementos de canal conformes deben resolver la configuración y las credenciales en cada punto de uso. - No puede adoptar el nombre de una herramienta ya registrada. El registro rechaza el plugin en conflicto en lugar de registrar su herramienta, dentro de los límites descritos en Conflictos de nombres de herramientas.
Los límites del entorno aislado y del espacio de nombres se mantienen independientemente de lo que intente el código del plugin. La regla de no retención forma parte, en cambio, del contrato de confianza entre el canal y el plugin, por lo que la revisión del editor y la política de firmas siguen siendo importantes.