Building plugins

Plugins de ferramentas

defineToolPlugin cria um plugin que adiciona apenas ferramentas que podem ser chamadas pelo agente: sem canal, provedor de modelo, hook, serviço ou backend de configuração. Ele gera os metadados de manifesto necessários para que o OpenClaw descubra ferramentas sem carregar o código de runtime do plugin.

Para plugins de provedor, canal, hook, serviço ou com recursos mistos, comece por Criação de plugins, Plugins de canal ou Plugins de provedor.

Requisitos

  • Node 22.22.3+, Node 24.15+ ou Node 25.9+.
  • Saída de pacote TypeScript ESM.
  • typebox em dependencies (não apenas devDependencies — o plugin gerado o importa durante o runtime).
  • openclaw >=2026.5.17, a primeira versão que exporta openclaw/plugin-sdk/tool-plugin.
  • Uma raiz de pacote que distribua dist/, openclaw.plugin.json e package.json.

Início rápido

bash
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm test

plugins init gera a estrutura inicial:

Arquivo Finalidade
src/index.ts Entrada defineToolPlugin com uma ferramenta echo
src/index.test.ts Teste de metadados que verifica a lista de ferramentas
tsconfig.json Saída TypeScript NodeNext em dist/
vitest.config.ts Configuração do Vitest para src/**/*.test.ts
package.json Scripts, dependências de runtime, openclaw.extensions: ["./dist/index.js"]
openclaw.plugin.json Metadados de manifesto gerados para a ferramenta inicial

npm run plugin:build executa npm run build (tsc) e depois openclaw plugins build --entry ./dist/index.js. npm run plugin:validate recompila e executa openclaw plugins validate --entry ./dist/index.js. Uma validação bem-sucedida exibe:

text
O plugin stock-quotes é válido.

Opções de openclaw plugins init <id>:

Flag Padrão Efeito
--directory <path> <id> Diretório de saída
--name <name> <id> em formato de título Nome de exibição
--type <type> tool Tipo de estrutura inicial: tool ou provider
--force desativado Sobrescreve um diretório de saída existente

Escrever uma ferramenta

defineToolPlugin recebe a identidade do plugin, um esquema de configuração opcional e uma lista estática de ferramentas. Os tipos de parâmetros e configuração são inferidos dos esquemas TypeBox.

typescript
  export default defineToolPlugin({  id: "stock-quotes",  name: "Cotações de ações",  description: "Obtém snapshots de cotações de ações.",  configSchema: Type.Object({    apiKey: Type.Optional(Type.String({ description: "Chave da API de cotações." })),    baseUrl: Type.Optional(Type.String({ description: "URL base da API de cotações." })),  }),  tools: (tool) => [    tool({      name: "stock_quote",      label: "Cotação de ação",      description: "Obtém um snapshot de cotação de ação.",      parameters: Type.Object({        symbol: Type.String({ description: "Símbolo do ticker, por exemplo, OPEN." }),      }),      async execute({ symbol }, config, context) {        context.signal?.throwIfAborted();        return {          symbol: symbol.toUpperCase(),          configured: Boolean(config.apiKey),          baseUrl: config.baseUrl ?? "https://api.example.com",        };      },    }),  ],});

Os nomes das ferramentas são a API estável. Escolha nomes exclusivos, em letras minúsculas e específicos o suficiente para evitar colisões com ferramentas do núcleo ou de outros plugins.

Ferramentas opcionais e de fábrica

Defina optional: true quando os usuários precisarem incluir explicitamente a ferramenta na lista de permissões antes que ela seja enviada a um modelo. openclaw plugins build grava a entrada de manifesto toolMetadata.<tool>.optional correspondente, para que o OpenClaw possa identificar que a ferramenta é opcional sem carregar o código de runtime do plugin.

typescript
tool({  name: "workflow_run",  description: "Executa um workflow externo.",  parameters: Type.Object({ goal: Type.String() }),  optional: true,  execute: ({ goal }) => ({ queued: true, goal }),});

Use factory quando uma ferramenta precisar do contexto de ferramenta do runtime antes de poder ser criada — para não participar de uma execução específica, inspecionar o estado do sandbox ou vincular helpers de runtime. Os metadados permanecem estáticos, embora a ferramenta concreta seja criada durante o runtime.

typescript
tool({  name: "local_workflow",  description: "Executa um workflow local fora de sessões em sandbox.",  parameters: Type.Object({ goal: Type.String() }),  optional: true,  factory({ api, toolContext }) {    if (toolContext.sandboxed) {      return null;    }    return createLocalWorkflowTool(api);  },});

As fábricas ainda declaram antecipadamente um nome de ferramenta fixo. Use definePluginEntry diretamente quando o plugin calcular nomes de ferramentas dinamicamente ou combinar ferramentas com hooks, serviços, provedores ou comandos.

Valores de retorno

defineToolPlugin encapsula valores de retorno simples no formato de resultado de ferramenta do OpenClaw:

  • Retorne uma string quando o modelo precisar ver exatamente esse texto.
  • Retorne um valor compatível com JSON quando quiser que o modelo veja JSON formatado e que o OpenClaw mantenha o valor original em details.
typescript
tool({  name: "echo_text",  description: "Repete o texto de entrada.",  parameters: Type.Object({    input: Type.String(),  }),  execute: ({ input }) => input,});
typescript
tool({  name: "echo_json",  description: "Repete a entrada como JSON estruturado.",  parameters: Type.Object({    input: Type.String(),  }),  execute: ({ input }) => ({ input, length: input.length }),});

Use uma ferramenta de fábrica quando precisar de um AgentToolResult personalizado ou quiser reutilizar uma implementação api.registerTool existente.

Configuração

configSchema é opcional. Omita-o e o OpenClaw aplicará um esquema estrito de objeto vazio; o manifesto gerado ainda incluirá configSchema.

typescript
export default defineToolPlugin({  id: "no-config-tools",  name: "Ferramentas sem configuração",  description: "Adiciona ferramentas que não precisam de configuração.",  tools: () => [],});

Com um configSchema, o segundo argumento de execute tem seu tipo derivado dele:

typescript
const configSchema = Type.Object({  apiKey: Type.String(),}); export default defineToolPlugin({  id: "configured-tools",  name: "Ferramentas configuradas",  description: "Adiciona ferramentas configuradas.",  configSchema,  tools: (tool) => [    tool({      name: "configured_ping",      description: "Verifica se a configuração está disponível.",      parameters: Type.Object({}),      execute: (_params, config) => ({ hasKey: config.apiKey.length > 0 }),    }),  ],});

O OpenClaw lê a configuração do plugin na entrada correspondente ao plugin na configuração do Gateway. Não codifique segredos diretamente no código-fonte nem nos exemplos da documentação; use configuração, variáveis de ambiente ou SecretRefs, conforme o modelo de segurança do plugin.

Metadados gerados

O OpenClaw precisa ler o manifesto do plugin antes de importar seu código de runtime. defineToolPlugin expõe metadados estáticos para isso, e openclaw plugins build os grava no pacote. Execute novamente o gerador após alterar o id, o nome, a descrição, o esquema de configuração, a ativação ou os nomes das ferramentas do plugin:

bash
npm run buildopenclaw plugins build --entry ./dist/index.js

Manifesto gerado para um plugin com uma ferramenta:

json
{  "id": "stock-quotes",  "name": "Cotações de ações",  "description": "Obtém snapshots de cotações de ações.",  "version": "0.1.0",  "configSchema": {    "type": "object",    "additionalProperties": false,    "properties": {}  },  "activation": {    "onStartup": true  },  "contracts": {    "tools": ["stock_quote"]  }}

contracts.tools é o contrato de descoberta importante: ele informa ao OpenClaw qual plugin é proprietário de cada ferramenta sem carregar o runtime de todos os plugins instalados. Um manifesto desatualizado pode fazer uma ferramenta desaparecer da descoberta ou fazer com que um erro de registro seja atribuído ao plugin errado.

Metadados do pacote

openclaw plugins build também alinha package.json à entrada de runtime selecionada:

json
{  "type": "module",  "files": ["dist", "openclaw.plugin.json", "README.md"],  "dependencies": {    "typebox": "^1.1.38"  },  "peerDependencies": {    "openclaw": ">=2026.5.17"  },  "openclaw": {    "extensions": ["./dist/index.js"]  }}

Distribua o JavaScript compilado (./dist/index.js), não uma entrada de código-fonte TypeScript. Entradas de código-fonte funcionam apenas no desenvolvimento local no workspace.

Validar na CI

plugins build --check falha sem regravar arquivos quando os metadados gerados estão desatualizados:

bash
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm test

plugins validate verifica se:

  • openclaw.plugin.json existe e passa pelo carregador normal de manifestos.
  • A entrada atual exporta os metadados defineToolPlugin.
  • Os campos do manifesto gerado correspondem aos metadados da entrada.
  • contracts.tools corresponde aos nomes de ferramentas declarados.
  • package.json aponta openclaw.extensions para a entrada de runtime selecionada.

Instalar e inspecionar localmente

Em outro checkout do OpenClaw ou usando uma CLI instalada, instale o caminho do pacote:

bash
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtime

Para um teste de fumaça do pacote, primeiro empacote e instale o tarball:

bash
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --json

Após a instalação, reinicie ou recarregue o Gateway e peça ao agente para usar a ferramenta. Se a ferramenta não estiver visível, inspecione o runtime do plugin e o catálogo efetivo de ferramentas antes de alterar o código (consulte Solução de problemas).

Publicar

Publique por meio do ClawHub quando o pacote estiver pronto. clawhub package publish recebe uma origem: uma pasta local, um repositório do GitHub (owner/repo[@ref]) ou uma URL de tarball.

bash
clawhub package publish ./stock-quotes --dry-runclawhub package publish ./stock-quotes

Instale com um localizador explícito do ClawHub:

bash
openclaw plugins install clawhub:your-org/stock-quotes

As especificações simples de pacotes npm ainda são instaladas pelo npm durante a transição de lançamento, mas o ClawHub é a superfície preferencial de descoberta e distribuição para plugins do OpenClaw. Consulte Publicação no ClawHub para informações sobre o escopo do proprietário e a revisão da versão.

Solução de problemas

plugin entry not found: ./dist/index.js

O arquivo de entrada selecionado não existe. Execute npm run build e depois execute novamente openclaw plugins build --entry ./dist/index.js ou openclaw plugins validate --entry ./dist/index.js.

plugin entry does not expose defineToolPlugin metadata

A entrada não exportou um valor criado por defineToolPlugin. Confirme se a exportação padrão do módulo é o resultado de defineToolPlugin(...) ou informe a entrada correta com --entry.

openclaw.plugin.json generated metadata is stale

O manifesto não corresponde mais aos metadados da entrada. Execute:

bash
npm run buildopenclaw plugins build --entry ./dist/index.js

Faça commit das alterações em openclaw.plugin.json e package.json.

package.json openclaw.extensions must include ./dist/index.js

Os metadados do pacote apontam para uma entrada de runtime diferente. Execute openclaw plugins build --entry ./dist/index.js para que o gerador alinhe os metadados do pacote à entrada que você pretende distribuir.

Cannot find package 'typebox'

O plugin compilado importa typebox durante o runtime. Mantenha-o em dependencies, reinstale, recompile e execute novamente a validação.

A ferramenta não aparece após a instalação

Verifique estes itens na ordem:

  1. openclaw plugins inspect <plugin-id> --runtime
  2. openclaw plugins validate --root <plugin-root> --entry ./dist/index.js
  3. openclaw.plugin.json tem contracts.tools com os nomes de ferramentas esperados.
  4. package.json tem openclaw.extensions: ["./dist/index.js"].
  5. O Gateway foi reiniciado ou recarregado após a instalação do plugin.

Consulte também

Was this useful?
On this page

On this page