Plugins (extensiones)
Inicio rápido (¿nuevo con plugins?)
Un plugin es simplemente un pequeño módulo de código que extiende OpenClaw con funciones extra (comandos, herramientas y RPC del Gateway).
La mayoría de las veces, usarás plugins cuando quieras una función que aún no está integrada en el core de OpenClaw (o quieras mantener funciones opcionales fuera de tu instalación principal).
Ruta rápida:
- Mira lo que ya está cargado:
openclaw plugins list
- Instala un plugin oficial (ejemplo: Voice Call):
openclaw plugins install @openclaw/voice-call
Las especificaciones npm son solo de registro (nombre de paquete + versión exacta opcional o dist-tag). Las especificaciones Git/URL/archivo y los rangos semver se rechazan.
Las especificaciones sin decorar y @latest se mantienen en el canal estable. Si npm resuelve cualquiera de
esas a un prerelease, OpenClaw se detiene y te pide que optes explícitamente con un
tag de prerelease como @beta/@rc o una versión de prerelease exacta.
- Reinicia el Gateway, luego configura bajo
plugins.entries.<id>.config.
Consulta Voice Call para un ejemplo concreto de plugin. ¿Buscas listados de terceros? Consulta Plugins de la comunidad.
Arquitectura
El sistema de plugins de OpenClaw tiene cuatro capas:
- Manifiesto + descubrimiento
OpenClaw encuentra plugins candidatos desde rutas configuradas, raíces de workspace,
raíces de extensiones globales y extensiones incluidas. El descubrimiento lee
openclaw.plugin.jsonmás los metadatos del paquete primero. - Habilitación + validación El core decide si un plugin descubierto está habilitado, deshabilitado, bloqueado o seleccionado para un slot exclusivo como memory.
- Carga en runtime Los plugins habilitados se cargan en proceso mediante jiti y registran capacidades en un registro central.
- Consumo de superficie El resto de OpenClaw lee el registro para exponer herramientas, canales, configuración de proveedor, hooks, rutas HTTP, comandos CLI y servicios.
El límite de diseño importante:
- el descubrimiento + validación de configuración debe funcionar desde metadatos de manifiesto/esquema sin ejecutar código del plugin
- el comportamiento en runtime viene de la ruta
register(api)del módulo del plugin
Esa separación permite a OpenClaw validar configuración, explicar plugins faltantes/deshabilitados, y construir hints de UI/esquema antes de que el runtime completo esté activo.
Modelo de ejecución
Los plugins se ejecutan en proceso con el Gateway. No están en sandbox. Un plugin cargado tiene el mismo límite de confianza a nivel de proceso que el código core.
Implicaciones:
- un plugin puede registrar herramientas, handlers de red, hooks y servicios
- un bug de plugin puede crashear o desestabilizar el gateway
- un plugin malicioso equivale a ejecución arbitraria de código dentro del proceso de OpenClaw
Usa listas de permitidos y rutas explícitas de instalación/carga para plugins no incluidos. Trata los plugins de workspace como código de desarrollo, no como valores por defecto de producción.
Nota importante de confianza:
plugins.allowconfía en ids de plugins, no en procedencia de origen.- Un plugin de workspace con el mismo id que un plugin incluido intencionalmente sobreescribe la copia incluida cuando ese plugin de workspace está habilitado/en lista de permitidos.
- Esto es normal y útil para desarrollo local, pruebas de parches y hotfixes.
Plugins disponibles (oficiales)
- Microsoft Teams es solo plugin desde 2026.1.15; instala
@openclaw/msteamssi usas Teams. - Memory (Core) — plugin de búsqueda de memoria incluido (habilitado por defecto con
plugins.slots.memory) - Memory (LanceDB) — plugin de memoria a largo plazo incluido (auto-recall/capture; configura
plugins.slots.memory = "memory-lancedb") - Voice Call —
@openclaw/voice-call - Zalo Personal —
@openclaw/zalouser - Matrix —
@openclaw/matrix - Nostr —
@openclaw/nostr - Zalo —
@openclaw/zalo - Microsoft Teams —
@openclaw/msteams - Google Antigravity OAuth (auth de proveedor) — incluido como
google-antigravity-auth(deshabilitado por defecto) - Gemini CLI OAuth (auth de proveedor) — incluido como
google-gemini-cli-auth(deshabilitado por defecto) - Qwen OAuth (auth de proveedor) — incluido como
qwen-portal-auth(deshabilitado por defecto) - Copilot Proxy (auth de proveedor) — puente local de VS Code Copilot Proxy; distinto del login por dispositivo
github-copilotintegrado (incluido, deshabilitado por defecto)
Los plugins de OpenClaw son módulos TypeScript cargados en runtime mediante jiti. La validación de configuración no ejecuta código del plugin; usa el manifiesto del plugin y JSON Schema en su lugar. Consulta Manifiesto de plugin.
Los plugins pueden registrar:
- Métodos RPC del Gateway
- Rutas HTTP del Gateway
- Herramientas de agente
- Comandos CLI
- Servicios en segundo plano
- Motores de contexto
- Validación de configuración opcional
- Skills (listando directorios
skillsen el manifiesto del plugin) - Comandos de auto-respuesta (se ejecutan sin invocar al agente de IA)
Los plugins se ejecutan en proceso con el Gateway, así que trátalos como código confiable. Guía de autoría de herramientas: Herramientas de agente de plugin.
Pipeline de carga
Al iniciar, OpenClaw hace aproximadamente esto:
- descubrir raíces candidatas de plugins
- leer
openclaw.plugin.jsony metadatos del paquete - rechazar candidatos inseguros
- normalizar configuración de plugins (
plugins.enabled,allow,deny,entries,slots,load.paths) - decidir habilitación para cada candidato
- cargar módulos habilitados mediante jiti
- llamar
register(api)y recoger registros en el registro de plugins - exponer el registro a comandos/superficies de runtime
Las puertas de seguridad ocurren antes de la ejecución en runtime. Los candidatos se bloquean cuando la entrada escapa de la raíz del plugin, la ruta es world-writable, o la propiedad de la ruta parece sospechosa para plugins no incluidos.
Comportamiento manifiesto-primero
El manifiesto es la fuente de verdad del plano de control. OpenClaw lo usa para:
- identificar el plugin
- descubrir canales/skills/esquema de configuración declarados
- validar
plugins.entries.<id>.config - enriquecer labels/placeholders de la UI de Control
- mostrar metadatos de instalación/catálogo
El módulo de runtime es la parte del plano de datos. Registra comportamiento real como hooks, herramientas, comandos o flujos de proveedor.
Lo que cachea el loader
OpenClaw mantiene cachés cortas en proceso para:
- resultados de descubrimiento
- datos del registro de manifiestos
- registros de plugins cargados
Estas cachés reducen la sobrecarga de inicio bursty y comandos repetidos. Son seguras de considerar como cachés de rendimiento de corta vida, no persistencia.
Helpers de runtime
Los plugins pueden acceder a helpers core selectos mediante api.runtime. Para TTS de telefonía:
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
Notas:
- Usa la configuración core de
messages.tts(OpenAI o ElevenLabs). - Devuelve buffer de audio PCM + sample rate. Los plugins deben re-muestrear/codificar para proveedores.
- Edge TTS no está admitido para telefonía.
Para STT/transcripción, los plugins pueden llamar:
const { text } = await api.runtime.stt.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// Opcional cuando el MIME no se puede inferir de forma confiable:
mime: "audio/ogg",
});
Notas:
- Usa la configuración core de comprensión de medios de audio (
tools.media.audio) y el orden de fallback de proveedores. - Devuelve
{ text: undefined }cuando no se produce salida de transcripción (por ejemplo, entrada omitida/no admitida).
Rutas HTTP del Gateway
Los plugins pueden exponer endpoints HTTP con api.registerHttpRoute(...).
api.registerHttpRoute({
path: "/acme/webhook",
auth: "plugin",
match: "exact",
handler: async (_req, res) => {
res.statusCode = 200;
res.end("ok");
return true;
},
});
Campos de ruta:
path: ruta bajo el servidor HTTP del gateway.auth: obligatorio. Usa"gateway"para requerir auth normal del gateway, o"plugin"para auth/verificación de webhook gestionada por el plugin.match: opcional."exact"(por defecto) o"prefix".replaceExisting: opcional. Permite al mismo plugin reemplazar su propio registro de ruta existente.handler: devuelvetruecuando la ruta gestionó la solicitud.
Notas:
api.registerHttpHandler(...)está obsoleto. Usaapi.registerHttpRoute(...).- Las rutas de plugins deben declarar
authexplícitamente. - Los conflictos exactos de
path + matchse rechazan a menos quereplaceExisting: true, y un plugin no puede reemplazar la ruta de otro plugin. - Las rutas solapadas con diferentes niveles de
authse rechazan. Mantén las cadenas de fallthroughexact/prefixen el mismo nivel de auth solamente.
Rutas de importación del SDK de plugins
Usa subrutas del SDK en lugar de la importación monolítica openclaw/plugin-sdk cuando
desarrolles plugins:
openclaw/plugin-sdk/corepara APIs genéricas de plugins, tipos de auth de proveedor y helpers compartidos.openclaw/plugin-sdk/compatpara código de plugins incluidos/internos que necesita helpers de runtime compartidos más amplios quecore.openclaw/plugin-sdk/telegrampara plugins de canal de Telegram.openclaw/plugin-sdk/discordpara plugins de canal de Discord.openclaw/plugin-sdk/slackpara plugins de canal de Slack.openclaw/plugin-sdk/signalpara plugins de canal de Signal.openclaw/plugin-sdk/imessagepara plugins de canal de iMessage.openclaw/plugin-sdk/whatsapppara plugins de canal de WhatsApp.openclaw/plugin-sdk/linepara plugins de canal de LINE.openclaw/plugin-sdk/msteamspara la superficie del plugin de Microsoft Teams incluido.- También están disponibles subrutas específicas de extensiones incluidas:
openclaw/plugin-sdk/acpx,openclaw/plugin-sdk/bluebubbles,openclaw/plugin-sdk/copilot-proxy,openclaw/plugin-sdk/device-pair,openclaw/plugin-sdk/diagnostics-otel,openclaw/plugin-sdk/diffs,openclaw/plugin-sdk/feishu,openclaw/plugin-sdk/google-gemini-cli-auth,openclaw/plugin-sdk/googlechat,openclaw/plugin-sdk/irc,openclaw/plugin-sdk/llm-task,openclaw/plugin-sdk/lobster,openclaw/plugin-sdk/matrix,openclaw/plugin-sdk/mattermost,openclaw/plugin-sdk/memory-core,openclaw/plugin-sdk/memory-lancedb,openclaw/plugin-sdk/minimax-portal-auth,openclaw/plugin-sdk/nextcloud-talk,openclaw/plugin-sdk/nostr,openclaw/plugin-sdk/open-prose,openclaw/plugin-sdk/phone-control,openclaw/plugin-sdk/qwen-portal-auth,openclaw/plugin-sdk/synology-chat,openclaw/plugin-sdk/talk-voice,openclaw/plugin-sdk/test-utils,openclaw/plugin-sdk/thread-ownership,openclaw/plugin-sdk/tlon,openclaw/plugin-sdk/twitch,openclaw/plugin-sdk/voice-call,openclaw/plugin-sdk/zaloyopenclaw/plugin-sdk/zalouser.
Nota de compatibilidad:
openclaw/plugin-sdksigue admitido para plugins externos existentes.- Los plugins nuevos y migrados incluidos deben usar subrutas específicas de canal o extensión;
usa
corepara superficies genéricas ycompatsolo cuando se necesiten helpers compartidos más amplios.
Inspección de canal de solo lectura
Si tu plugin registra un canal, prefiere implementar
plugin.config.inspectAccount(cfg, accountId) junto con resolveAccount(...).
Por qué:
resolveAccount(...)es la ruta de runtime. Puede asumir que las credenciales están completamente materializadas y puede fallar rápido cuando faltan secretos requeridos.- Las rutas de comandos de solo lectura como
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolvey los flujos de doctor/reparación de config no deberían necesitar materializar credenciales de runtime solo para describir la configuración.
Comportamiento recomendado de inspectAccount(...):
- Devolver solo estado descriptivo de la cuenta.
- Preservar
enabledyconfigured. - Incluir campos de origen/estado de credenciales cuando sea relevante, como:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- No necesitas devolver valores raw de tokens solo para reportar disponibilidad
de solo lectura. Devolver
tokenStatus: "available"(y el campo de origen correspondiente) es suficiente para comandos tipo status. - Usa
configured_unavailablecuando una credencial está configurada mediante SecretRef pero no está disponible en la ruta de comando actual.
Esto permite que los comandos de solo lectura reporten “configurado pero no disponible en esta ruta de comando” en vez de crashear o reportar incorrectamente la cuenta como no configurada.
Nota de rendimiento:
- El descubrimiento de plugins y los metadatos de manifiestos usan cachés cortas en proceso para reducir el trabajo bursty de inicio/recarga.
- Configura
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1oOPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1para desactivar estas cachés. - Ajusta las ventanas de caché con
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MSyOPENCLAW_PLUGIN_MANIFEST_CACHE_MS.
Descubrimiento y precedencia
OpenClaw escanea, en orden:
- Rutas de configuración
plugins.load.paths(archivo o directorio)
- Extensiones de workspace
<workspace>/.openclaw/extensions/*.ts<workspace>/.openclaw/extensions/*/index.ts
- Extensiones globales
~/.openclaw/extensions/*.ts~/.openclaw/extensions/*/index.ts
- Extensiones incluidas (distribuidas con OpenClaw, mayormente deshabilitadas por defecto)
<openclaw>/extensions/*
La mayoría de los plugins incluidos deben habilitarse explícitamente mediante
plugins.entries.<id>.enabled o openclaw plugins enable <id>.
Excepciones de plugins incluidos habilitados por defecto:
device-pairphone-controltalk-voice- plugin de slot de memoria activo (slot por defecto:
memory-core)
Los plugins instalados están habilitados por defecto, pero se pueden deshabilitar de la misma forma.
Los plugins de workspace están deshabilitados por defecto a menos que los habilites o los pongas en la lista de permitidos explícitamente. Esto es intencional: un repositorio clonado no debería convertirse silenciosamente en código del gateway de producción.
Notas de fortalecimiento:
- Si
plugins.allowestá vacío y hay plugins no incluidos descubribles, OpenClaw registra una advertencia de inicio con ids y orígenes de plugins. - Las rutas candidatas se verifican por seguridad antes de la admisión al descubrimiento. OpenClaw bloquea candidatos cuando:
- la entrada de extensión se resuelve fuera de la raíz del plugin (incluyendo escapes por symlink/traversal de ruta),
- la raíz/ruta de origen del plugin es world-writable,
- la propiedad de la ruta es sospechosa para plugins no incluidos (el propietario POSIX no es ni el uid actual ni root).
- Los plugins no incluidos cargados sin procedencia de install/load-path emiten una advertencia para que puedas fijar confianza (
plugins.allow) o seguimiento de instalación (plugins.installs).
Cada plugin debe incluir un archivo openclaw.plugin.json en su raíz. Si una ruta
apunta a un archivo, la raíz del plugin es el directorio del archivo y debe contener el
manifiesto.
Si múltiples plugins se resuelven al mismo id, la primera coincidencia en el orden anterior gana y las copias de menor precedencia se ignoran.
Esto significa:
- los plugins de workspace intencionalmente sobreescriben plugins incluidos con el mismo id
plugins.allow: ["foo"]autoriza el pluginfooactivo por id, incluso cuando la copia activa viene del workspace en vez de la raíz de extensiones incluidas- si necesitas control de procedencia más estricto, usa rutas explícitas de install/load e inspecciona el origen del plugin resuelto antes de habilitarlo
Reglas de habilitación
La habilitación se resuelve después del descubrimiento:
plugins.enabled: falsedeshabilita todos los pluginsplugins.denysiempre ganaplugins.entries.<id>.enabled: falsedeshabilita ese plugin- los plugins de origen workspace están deshabilitados por defecto
- las listas de permitidos restringen el conjunto activo cuando
plugins.allowno está vacío - las listas de permitidos son basadas en id, no en origen
- los plugins incluidos están deshabilitados por defecto a menos que:
- el id incluido esté en el conjunto de habilitados por defecto, o
- lo habilites explícitamente, o
- la configuración de canal habilite implícitamente el plugin de canal incluido
- los slots exclusivos pueden forzar-habilitar el plugin seleccionado para ese slot
En el core actual, los ids incluidos habilitados por defecto incluyen helpers locales/de proveedor como
ollama, sglang, vllm, más device-pair, phone-control y
talk-voice.
Packs de paquetes
Un directorio de plugin puede incluir un package.json con openclaw.extensions:
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"]
}
}
Cada entrada se convierte en un plugin. Si el pack lista múltiples extensiones, el id del plugin
se convierte en name/<fileBase>.
Si tu plugin importa dependencias npm, instálalas en ese directorio para que
node_modules esté disponible (npm install / pnpm install).
Protección de seguridad: cada entrada de openclaw.extensions debe permanecer dentro del directorio del plugin
después de la resolución de symlinks. Las entradas que escapan del directorio del paquete se
rechazan.
Nota de seguridad: openclaw plugins install instala dependencias de plugins con
npm install --ignore-scripts (sin scripts de ciclo de vida). Mantén los árboles de dependencias de plugins
“JS/TS puros” y evita paquetes que requieran builds postinstall.
Metadatos de catálogo de canal
Los plugins de canal pueden anunciar metadatos de onboarding mediante openclaw.channel e
indicaciones de instalación mediante openclaw.install. Esto mantiene el catálogo core libre de datos.
Ejemplo:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk (self-hosted)",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "extensions/nextcloud-talk",
"defaultChoice": "npm"
}
}
}
OpenClaw también puede fusionar catálogos de canal externos (por ejemplo, una exportación de registro MPM). Coloca un archivo JSON en una de estas ubicaciones:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
O apunta OPENCLAW_PLUGIN_CATALOG_PATHS (o OPENCLAW_MPM_CATALOG_PATHS) a
uno o más archivos JSON (delimitados por coma/punto y coma/PATH). Cada archivo debe
contener { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }.
IDs de plugins
IDs de plugin por defecto:
- Packs de paquetes:
package.jsonname - Archivo standalone: nombre base del archivo (
~/.../voice-call.ts->voice-call)
Si un plugin exporta id, OpenClaw lo usa pero advierte cuando no coincide con el
id configurado.
Modelo de registro
Los plugins cargados no mutan directamente globals core arbitrarios. Se registran en un registro central de plugins.
El registro rastrea:
- registros de plugins (identidad, origen, procedencia, estado, diagnósticos)
- herramientas
- hooks legacy y hooks tipados
- canales
- proveedores
- handlers RPC del gateway
- rutas HTTP
- registradores CLI
- servicios en segundo plano
- comandos propiedad de plugins
Las funciones core entonces leen de ese registro en vez de hablar directamente con módulos de plugins. Esto mantiene la carga unidireccional:
- módulo de plugin -> registro en el registro
- runtime core -> consumo del registro
Esa separación importa para la mantenibilidad. Significa que la mayoría de las superficies core solo necesitan un punto de integración: “leer el registro”, no “caso especial para cada módulo de plugin”.
Configuración
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-extension"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } },
},
},
}
Campos:
enabled: toggle principal (por defecto: true)allow: lista de permitidos (opcional)deny: lista de denegados (opcional; deny gana)load.paths: archivos/directorios extra de pluginsslots: selectores de slots exclusivos comomemoryycontextEngineentries.<id>: toggles por plugin + configuración
Los cambios de configuración requieren reinicio del gateway.
Reglas de validación (estrictas):
- Los ids de plugins desconocidos en
entries,allow,denyoslotsson errores. - Las claves
channels.<id>desconocidas son errores a menos que un manifiesto de plugin declare el id del canal. - La configuración del plugin se valida usando el JSON Schema embebido en
openclaw.plugin.json(configSchema). - Si un plugin está deshabilitado, su configuración se preserva y se emite una advertencia.
Deshabilitado vs faltante vs inválido
Estos estados son intencionalmente diferentes:
- deshabilitado: el plugin existe, pero las reglas de habilitación lo desactivaron
- faltante: la configuración referencia un id de plugin que el descubrimiento no encontró
- inválido: el plugin existe, pero su configuración no coincide con el esquema declarado
OpenClaw preserva la configuración de plugins deshabilitados para que reactivarlos no sea destructivo.
Slots de plugins (categorías exclusivas)
Algunas categorías de plugins son exclusivas (solo una activa a la vez). Usa
plugins.slots para seleccionar qué plugin posee el slot:
{
plugins: {
slots: {
memory: "memory-core", // o "none" para deshabilitar plugins de memoria
contextEngine: "legacy", // o un id de plugin como "lossless-claw"
},
},
}
Slots exclusivos admitidos:
memory: plugin de memoria activo ("none"deshabilita plugins de memoria)contextEngine: plugin de motor de contexto activo ("legacy"es el valor integrado por defecto)
Si múltiples plugins declaran kind: "memory" o kind: "context-engine", solo
el plugin seleccionado se carga para ese slot. Los demás se deshabilitan con diagnósticos.
Plugins de motor de contexto
Los plugins de motor de contexto gestionan la orquestación de contexto de sesión para ingestión, ensamblaje
y compactación. Regístralos desde tu plugin con
api.registerContextEngine(id, factory), luego selecciona el motor activo con
plugins.slots.contextEngine.
Usa esto cuando tu plugin necesite reemplazar o extender el pipeline de contexto por defecto en vez de solo agregar búsqueda de memoria o hooks.
UI de Control (esquema + labels)
La UI de Control usa config.schema (JSON Schema + uiHints) para renderizar mejores formularios.
OpenClaw enriquece uiHints en runtime basándose en los plugins descubiertos:
- Agrega labels por plugin para
plugins.entries.<id>/.enabled/.config - Fusiona hints opcionales de campos de configuración provistos por el plugin bajo:
plugins.entries.<id>.config.<field>
Si quieres que los campos de configuración de tu plugin muestren buenos labels/placeholders (y marquen secretos como sensibles),
proporciona uiHints junto a tu JSON Schema en el manifiesto del plugin.
Ejemplo:
{
"id": "my-plugin",
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": { "type": "string" },
"region": { "type": "string" }
}
},
"uiHints": {
"apiKey": { "label": "API Key", "sensitive": true },
"region": { "label": "Region", "placeholder": "us-east-1" }
}
}
CLI
openclaw plugins list
openclaw plugins info <id>
openclaw plugins install <path> # copiar un archivo/dir local a ~/.openclaw/extensions/<id>
openclaw plugins install ./extensions/voice-call # ruta relativa ok
openclaw plugins install ./plugin.tgz # instalar desde un tarball local
openclaw plugins install ./plugin.zip # instalar desde un zip local
openclaw plugins install -l ./extensions/voice-call # link (sin copia) para desarrollo
openclaw plugins install @openclaw/voice-call # instalar desde npm
openclaw plugins install @openclaw/voice-call --pin # almacenar nombre@versión exacta resuelta
openclaw plugins update <id>
openclaw plugins update --all
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins doctor
plugins update solo funciona para instalaciones npm rastreadas bajo plugins.installs.
Si los metadatos de integridad almacenados cambian entre actualizaciones, OpenClaw advierte y pide confirmación (usa --yes global para omitir prompts).
Los plugins también pueden registrar sus propios comandos de nivel superior (ejemplo: openclaw voicecall).
API de plugins (resumen)
Los plugins exportan ya sea:
- Una función:
(api) => { ... } - Un objeto:
{ id, name, configSchema, register(api) { ... } }
register(api) es donde los plugins adjuntan comportamiento. Los registros comunes incluyen:
registerToolregisterHookon(...)para hooks tipados de ciclo de vidaregisterChannelregisterProviderregisterHttpRouteregisterCommandregisterCliregisterContextEngineregisterService
Los plugins de motor de contexto también pueden registrar un gestor de contexto propiedad del runtime:
export default function (api) {
api.registerContextEngine("lossless-claw", () => ({
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
async ingest() {
return { ingested: true };
},
async assemble({ messages }) {
return { messages, estimatedTokens: 0 };
},
async compact() {
return { ok: true, compacted: false };
},
}));
}
Luego habilítalo en la configuración:
{
plugins: {
slots: {
contextEngine: "lossless-claw",
},
},
}
Hooks de plugins
Los plugins pueden registrar hooks en runtime. Esto permite a un plugin incluir automatización basada en eventos sin una instalación separada de pack de hooks.
Ejemplo
export default function register(api) {
api.registerHook(
"command:new",
async () => {
// Lógica del hook aquí.
},
{
name: "my-plugin.command-new",
description: "Runs when /new is invoked",
},
);
}
Notas:
- Registra hooks explícitamente mediante
api.registerHook(...). - Las reglas de elegibilidad de hooks siguen aplicándose (requisitos de OS/bins/env/config).
- Los hooks gestionados por plugins aparecen en
openclaw hooks listconplugin:<id>. - No puedes habilitar/deshabilitar hooks gestionados por plugins mediante
openclaw hooks; habilita/deshabilita el plugin en su lugar.
Hooks de ciclo de vida del agente (api.on)
Para hooks tipados de ciclo de vida del runtime, usa api.on(...):
export default function register(api) {
api.on(
"before_prompt_build",
(event, ctx) => {
return {
prependSystemContext: "Follow company style guide.",
};
},
{ priority: 10 },
);
}
Hooks importantes para la construcción de prompts:
before_model_resolve: se ejecuta antes de cargar la sesión (messagesno están disponibles). Úsalo para sobreescribir determinísticamentemodelOverrideoproviderOverride.before_prompt_build: se ejecuta después de cargar la sesión (messagesestán disponibles). Úsalo para dar forma a la entrada del prompt.before_agent_start: hook de compatibilidad legacy. Prefiere los dos hooks explícitos anteriores.
Política de hooks impuesta por el core:
- Los operadores pueden deshabilitar hooks de mutación de prompt por plugin con
plugins.entries.<id>.hooks.allowPromptInjection: false. - Cuando está deshabilitado, OpenClaw bloquea
before_prompt_builde ignora campos que mutan prompts devueltos desdebefore_agent_startlegacy mientras preservamodelOverrideyproviderOverridelegacy.
Campos de resultado de before_prompt_build:
prependContext: antepone texto al prompt de usuario para esta ejecución. Mejor para contenido específico del turno o dinámico.systemPrompt: sobreescritura completa del prompt del sistema.prependSystemContext: antepone texto al prompt del sistema actual.appendSystemContext: agrega texto al prompt del sistema actual.
Orden de construcción del prompt en runtime embebido:
- Aplicar
prependContextal prompt de usuario. - Aplicar sobreescritura de
systemPromptcuando se proporcione. - Aplicar
prependSystemContext + prompt del sistema actual + appendSystemContext.
Notas de merge y precedencia:
- Los handlers de hooks se ejecutan por prioridad (mayor primero).
- Para campos de contexto fusionados, los valores se concatenan en orden de ejecución.
- Los valores de
before_prompt_buildse aplican antes de los valores de fallback debefore_agent_startlegacy.
Guía de migración:
- Mueve las guías estáticas de
prependContextaprependSystemContext(oappendSystemContext) para que los proveedores puedan cachear contenido estable del prefijo del sistema. - Mantén
prependContextpara contexto dinámico por turno que deba permanecer vinculado al mensaje de usuario.
Plugins de proveedor (auth de modelo)
Los plugins pueden registrar proveedores de modelos para que los usuarios puedan ejecutar OAuth o configuración de clave API dentro de OpenClaw, mostrar la configuración del proveedor en onboarding/selectores de modelo, y contribuir al descubrimiento implícito de proveedores.
Los plugins de proveedor son la costura de extensión modular para la configuración de proveedores de modelos. Ya no son solo “helpers de OAuth”.
Ciclo de vida del plugin de proveedor
Un plugin de proveedor puede participar en cinco fases distintas:
- Auth
auth[].run(ctx)realiza OAuth, captura de clave API, código de dispositivo, o configuración personalizada y devuelve perfiles de auth más parches de config opcionales. - Configuración no interactiva
auth[].runNonInteractive(ctx)gestionaopenclaw onboard --non-interactivesin prompts. Usa esto cuando el proveedor necesita configuración headless personalizada más allá de las rutas simples integradas de clave API. - Integración con wizard
wizard.onboardingagrega una entrada aopenclaw onboard.wizard.modelPickeragrega una entrada de configuración al selector de modelos. - Descubrimiento implícito
discovery.run(ctx)puede contribuir configuración de proveedor automáticamente durante la resolución/listado de modelos. - Seguimiento post-selección
onModelSelected(ctx)se ejecuta después de elegir un modelo. Úsalo para trabajo específico del proveedor como descargar un modelo local.
Esta es la separación recomendada porque estas fases tienen diferentes requisitos de ciclo de vida:
- auth es interactivo y escribe credenciales/config
- la configuración no interactiva se basa en flags/env y no debe hacer prompts
- los metadatos del wizard son estáticos y orientados a la UI
- el descubrimiento debe ser seguro, rápido y tolerante a fallos
- los hooks post-selección son efectos secundarios vinculados al modelo elegido
Contrato de auth de proveedor
auth[].run(ctx) devuelve:
profiles: perfiles de auth para escribirconfigPatch: cambios opcionales aopenclaw.jsondefaultModel: referenciaprovider/modelopcionalnotes: notas opcionales orientadas al usuario
El core entonces:
- escribe los perfiles de auth devueltos
- aplica el cableado de config de perfil de auth
- fusiona el parche de config
- opcionalmente aplica el modelo por defecto
- ejecuta el hook
onModelSelecteddel proveedor cuando es apropiado
Esto significa que un plugin de proveedor posee la lógica de configuración específica del proveedor, mientras el core posee la ruta genérica de persistencia y merge de config.
Contrato no interactivo de proveedor
auth[].runNonInteractive(ctx) es opcional. Impleméntalo cuando el proveedor
necesite configuración headless que no se puede expresar mediante los flujos genéricos integrados
de clave API.
El contexto no interactivo incluye:
- la config actual y base
- opciones CLI de onboarding parseadas
- helpers de logging/error en runtime
- directorios de agente/workspace
resolveApiKey(...)para leer claves de proveedor desde flags, env o perfiles de auth existentes respetando--secret-input-modetoApiKeyCredential(...)para convertir una clave resuelta en una credencial de perfil de auth con el almacenamiento correcto de texto plano vs secret-ref
Usa esta superficie para proveedores como:
- runtimes auto-alojados compatibles con OpenAI que necesitan
--custom-base-url+--custom-model-id - verificación no interactiva o síntesis de config específica del proveedor
No hagas prompts desde runNonInteractive. Rechaza entradas faltantes con errores
accionables en su lugar.
Metadatos del wizard de proveedor
wizard.onboarding controla cómo aparece el proveedor en el onboarding agrupado:
choiceId: valor de auth-choicechoiceLabel: label de opciónchoiceHint: indicación cortagroupId: id de bucket de grupogroupLabel: label de grupogroupHint: indicación de grupomethodId: método de auth a ejecutar
wizard.modelPicker controla cómo aparece un proveedor como entrada de “configurar esto ahora”
en la selección de modelo:
labelhintmethodId
Cuando un proveedor tiene múltiples métodos de auth, el wizard puede apuntar a un método explícito o dejar que OpenClaw sintetice opciones por método.
OpenClaw valida los metadatos del wizard de proveedor cuando el plugin se registra:
- los ids de método de auth duplicados o en blanco se rechazan
- los metadatos del wizard se ignoran cuando el proveedor no tiene métodos de auth
- los bindings de
methodIdinválidos se degradan a advertencias y recurren a los métodos de auth restantes del proveedor
Contrato de descubrimiento de proveedor
discovery.run(ctx) devuelve uno de:
{ provider }{ providers }null
Usa { provider } para el caso común donde el plugin posee un id de proveedor.
Usa { providers } cuando un plugin descubre múltiples entradas de proveedor.
El contexto de descubrimiento incluye:
- la config actual
- directorios de agente/workspace
- env del proceso
- un helper para resolver la clave API del proveedor y un valor de clave API seguro para descubrimiento
El descubrimiento debe ser:
- rápido
- best-effort
- seguro de omitir en caso de fallo
- cuidadoso con efectos secundarios
No debe depender de prompts o configuración de larga duración.
Ordenamiento del descubrimiento
El descubrimiento de proveedores se ejecuta en fases ordenadas:
simpleprofilepairedlate
Usa:
simplepara descubrimiento barato solo de entornoprofilecuando el descubrimiento depende de perfiles de authpairedpara proveedores que necesitan coordinarse con otro paso de descubrimientolatepara sondeo costoso o de red local
La mayoría de los proveedores auto-alojados deben usar late.
Buenos límites de plugins de proveedor
Buen encaje para plugins de proveedor:
- proveedores locales/auto-alojados con flujos de configuración personalizados
- OAuth/código de dispositivo específico del proveedor
- descubrimiento implícito de servidores de modelos locales
- efectos secundarios post-selección como pulls de modelos
Encaje menos convincente:
- proveedores triviales de solo clave API que difieren solo en variable de env, URL base y un modelo por defecto
Esos aún pueden ser plugins, pero el principal beneficio de modularidad viene de extraer primero los proveedores ricos en comportamiento.
Registra un proveedor mediante api.registerProvider(...). Cada proveedor expone uno
o más métodos de auth (OAuth, clave API, código de dispositivo, etc.). Esos métodos pueden
alimentar:
openclaw models auth login --provider <id> [--method <id>]openclaw onboard- entradas de configuración de “proveedor personalizado” en el selector de modelos
- descubrimiento implícito de proveedores durante resolución/listado de modelos
Ejemplo:
api.registerProvider({
id: "acme",
label: "AcmeAI",
auth: [
{
id: "oauth",
label: "OAuth",
kind: "oauth",
run: async (ctx) => {
// Ejecutar flujo OAuth y devolver perfiles de auth.
return {
profiles: [
{
profileId: "acme:default",
credential: {
type: "oauth",
provider: "acme",
access: "...",
refresh: "...",
expires: Date.now() + 3600 * 1000,
},
},
],
defaultModel: "acme/opus-1",
};
},
},
],
wizard: {
onboarding: {
choiceId: "acme",
choiceLabel: "AcmeAI",
groupId: "acme",
groupLabel: "AcmeAI",
methodId: "oauth",
},
modelPicker: {
label: "AcmeAI (custom)",
hint: "Connect a self-hosted AcmeAI endpoint",
methodId: "oauth",
},
},
discovery: {
order: "late",
run: async () => ({
provider: {
baseUrl: "https://acme.example/v1",
api: "openai-completions",
apiKey: "${ACME_API_KEY}",
models: [],
},
}),
},
});
Notas:
runrecibe unProviderAuthContextcon helpersprompter,runtime,openUrlyoauth.createVpsAwareHandlers.runNonInteractiverecibe unProviderAuthMethodNonInteractiveContextcon helpersopts,resolveApiKeyytoApiKeyCredentialpara onboarding headless.- Devuelve
configPatchcuando necesites agregar modelos por defecto o config de proveedor. - Devuelve
defaultModelpara que--set-defaultpueda actualizar los defaults del agente. wizard.onboardingagrega una opción de proveedor aopenclaw onboard.wizard.modelPickeragrega una entrada de “configurar este proveedor” al selector de modelos.discovery.rundevuelve ya sea{ provider }para el id de proveedor propio del plugin o{ providers }para descubrimiento multi-proveedor.discovery.ordercontrola cuándo se ejecuta el proveedor en relación a las fases de descubrimiento integradas:simple,profile,pairedolate.onModelSelectedes el hook post-selección para trabajo de seguimiento específico del proveedor como descargar un modelo local.
Registrar un canal de mensajería
Los plugins pueden registrar plugins de canal que se comportan como canales integrados
(WhatsApp, Telegram, etc.). La configuración del canal vive bajo channels.<id> y es
validada por el código de tu plugin de canal.
const myChannel = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "demo channel plugin.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async () => ({ ok: true }),
},
};
export default function (api) {
api.registerChannel({ plugin: myChannel });
}
Notas:
- Pon la config bajo
channels.<id>(noplugins.entries). meta.labelse usa para labels en listas CLI/UI.meta.aliasesagrega ids alternativos para normalización e inputs CLI.meta.preferOverlista ids de canal a omitir en auto-enable cuando ambos están configurados.meta.detailLabelymeta.systemImagepermiten que las UIs muestren labels/iconos de canal más ricos.
Hooks de onboarding de canal
Los plugins de canal pueden definir hooks opcionales de onboarding en plugin.onboarding:
configure(ctx)es el flujo de configuración base.configureInteractive(ctx)puede poseer completamente la configuración interactiva tanto para estados configurados como no configurados.configureWhenConfigured(ctx)puede sobreescribir el comportamiento solo para canales ya configurados.
Precedencia de hooks en el wizard:
configureInteractive(si está presente)configureWhenConfigured(solo cuando el estado del canal ya está configurado)- fallback a
configure
Detalles del contexto:
configureInteractiveyconfigureWhenConfiguredreciben:configured(trueofalse)label(nombre del canal orientado al usuario utilizado por prompts)- más los campos compartidos de config/runtime/prompter/options
- Devolver
"skip"deja la selección y el seguimiento de cuenta sin cambios. - Devolver
{ cfg, accountId? }aplica actualizaciones de config y registra la selección de cuenta.
Escribir un nuevo canal de mensajería (paso a paso)
Usa esto cuando quieras una nueva superficie de chat (un “canal de mensajería”), no un proveedor de modelos.
La documentación de proveedores de modelos vive bajo /providers/*.
- Elige un id + forma de config
- Toda la config del canal vive bajo
channels.<id>. - Prefiere
channels.<id>.accounts.<accountId>para configuraciones multi-cuenta.
- Define los metadatos del canal
meta.label,meta.selectionLabel,meta.docsPath,meta.blurbcontrolan las listas CLI/UI.meta.docsPathdebe apuntar a una página de docs como/channels/<id>.meta.preferOverpermite que un plugin reemplace otro canal (auto-enable lo prefiere).meta.detailLabelymeta.systemImageson usados por UIs para texto/iconos de detalle.
- Implementa los adaptadores requeridos
config.listAccountIds+config.resolveAccountcapabilities(tipos de chat, media, hilos, etc.)outbound.deliveryMode+outbound.sendText(para envío básico)
- Agrega adaptadores opcionales según necesidad
setup(wizard),security(política DM),status(salud/diagnósticos)gateway(start/stop/login),mentions,threading,streamingactions(acciones de mensaje),commands(comportamiento de comandos nativos)
- Registra el canal en tu plugin
api.registerChannel({ plugin })
Ejemplo mínimo de config:
{
channels: {
acmechat: {
accounts: {
default: { token: "ACME_TOKEN", enabled: true },
},
},
},
}
Plugin mínimo de canal (solo saliente):
const plugin = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "AcmeChat messaging channel.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async ({ text }) => {
// entregar `text` a tu canal aquí
return { ok: true };
},
},
};
export default function (api) {
api.registerChannel({ plugin });
}
Carga el plugin (directorio de extensiones o plugins.load.paths), reinicia el gateway,
luego configura channels.<id> en tu config.
Herramientas de agente
Consulta la guía dedicada: Herramientas de agente de plugin.
Registrar un método RPC del gateway
export default function (api) {
api.registerGatewayMethod("myplugin.status", ({ respond }) => {
respond(true, { ok: true });
});
}
Registrar comandos CLI
export default function (api) {
api.registerCli(
({ program }) => {
program.command("mycmd").action(() => {
console.log("Hello");
});
},
{ commands: ["mycmd"] },
);
}
Registrar comandos de auto-respuesta
Los plugins pueden registrar comandos slash personalizados que se ejecutan sin invocar al agente de IA. Esto es útil para comandos toggle, verificaciones de estado o acciones rápidas que no necesitan procesamiento LLM.
export default function (api) {
api.registerCommand({
name: "mystatus",
description: "Show plugin status",
handler: (ctx) => ({
text: `Plugin is running! Channel: ${ctx.channel}`,
}),
});
}
Contexto del handler de comando:
senderId: El ID del remitente (si está disponible)channel: El canal donde se envió el comandoisAuthorizedSender: Si el remitente es un usuario autorizadoargs: Argumentos pasados después del comando (siacceptsArgs: true)commandBody: El texto completo del comandoconfig: La configuración actual de OpenClaw
Opciones del comando:
name: Nombre del comando (sin la/inicial)nativeNames: Aliases opcionales de comandos nativos para superficies slash/menú. Usadefaultpara todos los proveedores nativos, o claves específicas de proveedor comodiscorddescription: Texto de ayuda mostrado en listas de comandosacceptsArgs: Si el comando acepta argumentos (por defecto: false). Si es false y se proporcionan argumentos, el comando no coincide y el mensaje pasa a otros handlersrequireAuth: Si requiere remitente autorizado (por defecto: true)handler: Función que devuelve{ text: string }(puede ser async)
Ejemplo con autorización y argumentos:
api.registerCommand({
name: "setmode",
description: "Set plugin mode",
acceptsArgs: true,
requireAuth: true,
handler: async (ctx) => {
const mode = ctx.args?.trim() || "default";
await saveMode(mode);
return { text: `Mode set to: ${mode}` };
},
});
Notas:
- Los comandos de plugins se procesan antes que los comandos integrados y el agente de IA
- Los comandos se registran globalmente y funcionan en todos los canales
- Los nombres de comandos no distinguen mayúsculas de minúsculas (
/MyStatuscoincide con/mystatus) - Los nombres de comandos deben empezar con una letra y contener solo letras, números, guiones y guiones bajos
- Los nombres de comandos reservados (como
help,status,reset, etc.) no pueden ser sobreescritos por plugins - El registro duplicado de comandos entre plugins fallará con un error de diagnóstico
Registrar servicios en segundo plano
export default function (api) {
api.registerService({
id: "my-service",
start: () => api.logger.info("ready"),
stop: () => api.logger.info("bye"),
});
}
Convenciones de nombres
- Métodos del gateway:
pluginId.action(ejemplo:voicecall.status) - Herramientas:
snake_case(ejemplo:voice_call) - Comandos CLI: kebab o camel, pero evita colisiones con comandos core
Skills
Los plugins pueden incluir un skill en el repositorio (skills/<name>/SKILL.md).
Habilítalo con plugins.entries.<id>.enabled (u otros controles de config) y asegúrate de que
esté presente en las ubicaciones de skills de tu workspace/gestionados.
Distribución (npm)
Empaquetado recomendado:
- Paquete principal:
openclaw(este repositorio) - Plugins: paquetes npm separados bajo
@openclaw/*(ejemplo:@openclaw/voice-call)
Contrato de publicación:
- El
package.jsondel plugin debe incluiropenclaw.extensionscon uno o más archivos de entrada. - Los archivos de entrada pueden ser
.jso.ts(jiti carga TS en runtime). openclaw plugins install <npm-spec>usanpm pack, extrae en~/.openclaw/extensions/<id>/y lo habilita en la config.- Estabilidad de claves de config: los paquetes con scope se normalizan al id sin scope para
plugins.entries.*.
Plugin de ejemplo: Voice Call
Este repositorio incluye un plugin de llamada de voz (Twilio o log fallback):
- Fuente:
extensions/voice-call - Skill:
skills/voice-call - CLI:
openclaw voicecall start|status - Herramienta:
voice_call - RPC:
voicecall.start,voicecall.status - Config (twilio):
provider: "twilio"+twilio.accountSid/authToken/from(opcionalesstatusCallbackUrl,twimlUrl) - Config (dev):
provider: "log"(sin red)
Consulta Voice Call y extensions/voice-call/README.md para configuración y uso.
Notas de seguridad
Los plugins se ejecutan en proceso con el Gateway. Trátalos como código confiable:
- Solo instala plugins en los que confíes.
- Prefiere listas de permitidos
plugins.allow. - Recuerda que
plugins.allowes basado en id, así que un plugin de workspace habilitado puede intencionalmente sobreescribir un plugin incluido con el mismo id. - Reinicia el Gateway después de cambios.
Probar plugins
Los plugins pueden (y deberían) incluir tests:
- Los plugins in-repo pueden mantener tests de Vitest bajo
src/**(ejemplo:src/plugins/voice-call.plugin.test.ts). - Los plugins publicados por separado deben ejecutar su propio CI (lint/build/test) y validar que
openclaw.extensionsapunte al entrypoint construido (dist/index.js).