Building plugins
Plugins de herramientas
Los plugins de herramientas agregan herramientas invocables por agentes a OpenClaw sin agregar un canal,
proveedor de modelos, hook, servicio ni backend de configuración. Usa defineToolPlugin cuando el
plugin posee una lista fija de herramientas y quieres que OpenClaw genere los metadatos
del manifiesto que mantienen esas herramientas detectables sin cargar código de runtime.
El flujo recomendado es:
- Crea el esqueleto de un paquete con
openclaw plugins init. - Escribe herramientas con
defineToolPlugin. - Compila JavaScript.
- Genera los metadatos de
openclaw.plugin.jsonypackage.jsonconopenclaw plugins build. - Valida los metadatos generados antes de publicar o instalar.
Para plugins de proveedor, canal, hook, servicio o capacidades mixtas, empieza con Crear plugins, Plugins de canal, o Plugins de proveedor.
Requisitos
- Node >= 22.
- Salida de paquete TypeScript ESM.
typeboxpara esquemas de configuración y parámetros de herramientas.openclaw >=2026.5.17, la primera versión de OpenClaw que exportaopenclaw/plugin-sdk/tool-plugin.- Una raíz de paquete que pueda distribuir
dist/,openclaw.plugin.jsonypackage.json.
El plugin generado importa typebox en runtime, así que mantén typebox en
dependencies, no solo en devDependencies.
Inicio rápido
Crea un nuevo paquete de plugin:
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm testEl esqueleto crea:
src/index.ts: una entradadefineToolPlugincon una herramientaecho.src/index.test.ts: una pequeña prueba de metadatos.tsconfig.json: salida TypeScript NodeNext adist/.package.json: scripts, dependencias de runtime yopenclaw.extensions: ["./dist/index.js"].openclaw.plugin.json: metadatos de manifiesto generados para la herramienta inicial.
Salida de validación esperada:
Plugin stock-quotes is valid.Escribir una herramienta
defineToolPlugin recibe la identidad del plugin, un esquema de configuración opcional y una
lista estática de herramientas. Los tipos de parámetros y configuración se infieren de los
esquemas TypeBox.
export default defineToolPlugin({ id: "stock-quotes", name: "Stock Quotes", description: "Fetch stock quote snapshots.", configSchema: Type.Object({ apiKey: Type.Optional(Type.String({ description: "Quote API key." })), baseUrl: Type.Optional(Type.String({ description: "Quote API base URL." })), }), tools: (tool) => [ tool({ name: "stock_quote", label: "Stock Quote", description: "Fetch a stock quote snapshot.", parameters: Type.Object({ symbol: Type.String({ description: "Ticker symbol, for example OPEN." }), }), async execute({ symbol }, config, context) { context.signal?.throwIfAborted(); return { symbol: symbol.toUpperCase(), configured: Boolean(config.apiKey), baseUrl: config.baseUrl ?? "https://api.example.com", }; }, }), ],});Los nombres de herramientas son la API estable. Elige nombres que sean únicos, en minúsculas y lo bastante específicos para evitar colisiones con herramientas del núcleo u otros plugins.
Herramientas opcionales y de fábrica
Configura optional: true cuando los usuarios deban permitir explícitamente la herramienta antes de que
se envíe a un modelo:
tool({ name: "workflow_run", description: "Run an external workflow.", parameters: Type.Object({ goal: Type.String() }), optional: true, execute: ({ goal }) => ({ queued: true, goal }),});openclaw plugins build escribe la entrada de manifiesto toolMetadata.<tool>.optional
correspondiente, para que OpenClaw pueda detectar la herramienta sin cargar código de
runtime del plugin.
Usa factory cuando una herramienta necesita el contexto de herramienta de runtime antes de poder
crearse. La fábrica mantiene los metadatos estáticos mientras permite que la herramienta se excluya de una
ejecución específica, inspeccione el estado del sandbox o vincule helpers de runtime.
tool({ name: "local_workflow", description: "Run a local workflow outside sandboxed sessions.", parameters: Type.Object({ goal: Type.String() }), optional: true, factory({ api, toolContext }) { if (toolContext.sandboxed) { return null; } return createLocalWorkflowTool(api); },});Las fábricas siguen siendo para nombres de herramientas fijos. Usa definePluginEntry directamente cuando
el plugin calcule nombres de herramientas dinámicamente o combine herramientas con hooks,
servicios, proveedores, comandos u otras superficies de runtime.
Valores de retorno
defineToolPlugin envuelve valores de retorno simples en el formato de resultado de herramienta
de OpenClaw:
- Devuelve una cadena cuando el modelo deba ver ese texto exacto.
- Devuelve un valor compatible con JSON cuando quieras que el modelo vea JSON formateado
y que OpenClaw mantenga el valor original en
details.
tool({ name: "echo_text", description: "Echo input text.", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => input,});tool({ name: "echo_json", description: "Echo input as structured JSON.", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => ({ input, length: input.length }),});Usa una herramienta de fábrica cuando necesites devolver un AgentToolResult personalizado o reutilizar
una implementación existente de api.registerTool. Usa definePluginEntry en lugar de
defineToolPlugin cuando necesites herramientas totalmente dinámicas o capacidades de plugin
mixtas.
Configuración
configSchema es opcional. Si lo omites, OpenClaw usa un esquema estricto de objeto vacío
y el manifiesto generado sigue incluyendo configSchema.
export default defineToolPlugin({ id: "no-config-tools", name: "No Config Tools", description: "Adds tools that do not need configuration.", tools: () => [],});Cuando incluyes configSchema, el segundo argumento de execute se tipa a partir del
esquema:
const configSchema = Type.Object({ apiKey: Type.String(),}); export default defineToolPlugin({ id: "configured-tools", name: "Configured Tools", description: "Adds configured tools.", configSchema, tools: (tool) => [ tool({ name: "configured_ping", description: "Check whether configuration is available.", parameters: Type.Object({}), execute: (_params, config) => ({ hasKey: config.apiKey.length > 0 }), }), ],});OpenClaw lee la configuración del plugin desde la entrada del plugin en la configuración del Gateway. No codifiques secretos en el código fuente ni en ejemplos de documentación. Usa configuración, variables de entorno o SecretRefs según el modelo de seguridad del plugin.
Metadatos generados
OpenClaw detecta plugins instalados a partir de metadatos fríos. Debe poder leer
el manifiesto del plugin antes de importar el código de runtime del plugin. Por eso, defineToolPlugin
expone metadatos estáticos, y openclaw plugins build escribe esos
metadatos en el paquete.
Ejecuta el generador después de cambiar el id, nombre, descripción, esquema de configuración, activación o nombres de herramientas del plugin:
npm run buildopenclaw plugins build --entry ./dist/index.jsPara un plugin de una sola herramienta, el manifiesto generado se ve así:
{ "id": "stock-quotes", "name": "Stock Quotes", "description": "Fetch stock quote snapshots.", "version": "0.1.0", "configSchema": { "type": "object", "additionalProperties": false, "properties": {} }, "activation": { "onStartup": true }, "contracts": { "tools": ["stock_quote"] }}contracts.tools es el contrato de detección importante. Indica a OpenClaw qué
plugin posee cada herramienta sin cargar el runtime de todos los plugins instalados. Si el
manifiesto está obsoleto, la herramienta puede faltar en la detección o se puede atribuir al plugin
incorrecto un error de registro.
Metadatos del paquete
Para el flujo sencillo de plugin de herramientas, openclaw plugins build alinea
package.json con la única entrada de runtime seleccionada:
{ "type": "module", "files": ["dist", "openclaw.plugin.json", "README.md"], "dependencies": { "typebox": "^1.1.38" }, "peerDependencies": { "openclaw": ">=2026.5.17" }, "openclaw": { "extensions": ["./dist/index.js"] }}Usa JavaScript compilado como ./dist/index.js para paquetes instalados. Las entradas de
código fuente son útiles en el desarrollo dentro del workspace, pero los paquetes publicados no deben
depender de la carga de runtime de TypeScript.
Validar en CI
Usa plugins build --check para hacer fallar CI cuando los metadatos generados estén obsoletos sin
reescribir archivos:
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm testplugins validate comprueba que:
openclaw.plugin.jsonexista y pase el cargador de manifiestos normal.- La entrada actual exporte metadatos de
defineToolPlugin. - Los campos del manifiesto generado coincidan con los metadatos de la entrada.
contracts.toolscoincida con los nombres de herramientas declarados.package.jsonapunteopenclaw.extensionsa la entrada de runtime seleccionada.
Instalar e inspeccionar localmente
Desde un checkout separado de OpenClaw o una CLI instalada, instala la ruta del paquete:
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtimePara una prueba de humo empaquetada, empaqueta primero e instala el tarball:
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --jsonDespués de la instalación, inicia o reinicia el Gateway y pide al agente que use la herramienta. Si estás depurando la visibilidad de herramientas, inspecciona el runtime del plugin y el catálogo efectivo de herramientas antes de cambiar el código.
Publicar
Publica a través de ClawHub cuando el paquete esté listo:
clawhub package publish your-org/stock-quotes --dry-runclawhub package publish your-org/stock-quotesInstala con un localizador explícito de ClawHub:
openclaw plugins install clawhub:your-org/stock-quotesLas especificaciones simples de paquetes npm siguen siendo compatibles durante la transición de lanzamiento, pero ClawHub es la superficie preferida de detección y distribución para los plugins de OpenClaw.
Solución de problemas
plugin entry not found: ./dist/index.js
El archivo de entrada seleccionado no existe. Ejecuta npm run build y luego vuelve a ejecutar
openclaw plugins build --entry ./dist/index.js o
openclaw plugins validate --entry ./dist/index.js.
plugin entry does not expose defineToolPlugin metadata
La entrada no exportó un valor creado por defineToolPlugin. Comprueba que la
exportación predeterminada del módulo sea el resultado de defineToolPlugin(...), o pasa la
entrada correcta con --entry.
openclaw.plugin.json generated metadata is stale
El manifiesto ya no coincide con los metadatos de la entrada. Ejecuta:
npm run buildopenclaw plugins build --entry ./dist/index.jsConfirma tanto los cambios de openclaw.plugin.json como los de package.json.
package.json openclaw.extensions must include ./dist/index.js
Los metadatos del paquete apuntan a una entrada de runtime diferente. Ejecuta
openclaw plugins build --entry ./dist/index.js para que el generador alinee los
metadatos del paquete con la entrada que quieres distribuir.
Cannot find package 'typebox'
El plugin compilado importa typebox en runtime. Mantén typebox en
dependencies, reinstala las dependencias del paquete, recompila y vuelve a ejecutar la validación.
La herramienta no aparece después de instalar
Comprueba estos puntos en orden:
openclaw plugins inspect <plugin-id> --runtimeopenclaw plugins validate --root <plugin-root> --entry ./dist/index.jsopenclaw.plugin.jsontienecontracts.toolscon los nombres de herramientas esperados.package.jsontieneopenclaw.extensions: ["./dist/index.js"].- El Gateway se reinició o recargó después de instalar el plugin.