Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

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.

  1. Gate. Si [plugins] enabled es false, el cargador no hace nada. Este es la primera y más barata comprobación.
  2. Descubrir. El cargador escanea el directorio de plugins resuelto ([plugins] plugins_dir, por defecto ~/.zeroclaw/plugins/) en busca de subdirectorios que contengan un manifest.toml. Omite los directorios con prefijo de punto, incluido el directorio de preparación oculto en el que zeroclaw plugin install construye un paquete antes de renombrarlo a su ubicación definitiva, de modo que una instalación incompleta nunca se carga.
  3. Validar la estructura. Cada manifiesto debe declarar al menos una capacidad, y un plugin que no sea una skill debe indicar un wasm_path relativo 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.
  4. Aplicar la política de firmas. Cada plugin se comprueba frente a [plugins.security] signature_mode y trusted_publisher_keys configurados. Un plugin que no supera la política se descarta del conjunto cargado y no se expone como una herramienta.
  5. Admitir bytes ejecutables. El host abre el componente confinado una sola vez, verifica cualquier wasm_sha256 declarado y conserva esos bytes exactos. En el modo strict, 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 modo strict, el wasm_sha256 firmado 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.
  6. 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 defecto false, cierre por fallo): con enabled = true pero auto_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 con zeroclaw plugin bind, siguen activándose. El cargador de habilidades aplica la misma restricción de auto_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:

ModoQué cargaUsar cuando
disabledTodo plugin bien formado, firmado o noDesarrollo local con plugins que has creado tú mismo
permissiveTodo plugin bien formado; las firmas no firmadas, no confiables e inválidas se cargan con una advertenciaMigración hacia la firma sin romper las instalaciones existentes
strictSolo 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:

  1. Nombre del paquete. Un plugin cuyo nombre de paquete (el name del manifiesto) coincide con una herramienta ya registrada se rechaza antes de instanciar su componente. El host registra un evento WARN con error_key plugin_package_name_conflict en sus attributes.
  2. 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 WARN con error_key plugin_tool_name_conflict en sus attributes. 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 lleva error_key plugin_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, observer o skill. Un plugin tool aporta 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:

  1. Instala el paquete. zeroclaw plugin install <directory> para un paquete local, o zeroclaw 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> y zeroclaw plugin list --verify compilan 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.
  2. Activa el sistema de plugins. zeroclaw config set plugins.enabled true, y luego zeroclaw config set plugins.auto_discover true para 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 necesita plugins.enabled, una declaración [channels.plugin.<alias>] y un agente habilitado que incluya plugin.<alias> entre sus canales; auto_discover no interviene en ello. Para un paquete que replica un canal nativo mediante provides, 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.
  3. 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_approve del perfil de riesgo de ese agente, por ejemplo zeroclaw config set risk_profiles.default.auto_approve '["<tool-name>"]'. config set reemplaza la lista completa: los valores predeterminados integrados se vuelven a combinar en risk_profiles.default al 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é en always_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 en always_ask, que siempre vuelven a solicitar aprobación. Sin un aprobador, la llamada se deniega y no se ejecuta.
  4. Elige una política de firma. signature_mode se mantiene en disabled de forma predeterminada, para que un plugin que hayas creado tú mismo se instale sin gestión de claves. En modo strict, solo se cargan los paquetes firmados con una clave incluida en trusted_publisher_keys; y como el registro oficial publica actualmente paquetes sin firmar, ninguno se instala en modo strict hasta 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.get con ámbito restringido durante una llamada de servicio autorizada. Las herramientas obtienen acceso durante execute. Los canales reciben acceso a config.get y secrets.get durante configure y 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.