Building plugins
Plugins d’outils
Les Plugins d’outils ajoutent à OpenClaw des outils appelables par l’agent sans ajouter de canal,
de fournisseur de modèle, de hook, de service ni de backend de configuration. Utilisez defineToolPlugin lorsque le
Plugin possède une liste fixe d’outils et que vous voulez qu’OpenClaw génère les métadonnées de manifeste
qui gardent ces outils découvrables sans charger le code d’exécution.
Le flux recommandé est le suivant :
- Échafauder un paquet avec
openclaw plugins init. - Écrire les outils avec
defineToolPlugin. - Construire le JavaScript.
- Générer les métadonnées
openclaw.plugin.jsonetpackage.jsonavecopenclaw plugins build. - Valider les métadonnées générées avant publication ou installation.
Pour les Plugins de fournisseur, de canal, de hook, de service ou à capacités mixtes, commencez plutôt par Créer des Plugins, Plugins de canal, ou Plugins de fournisseur.
Prérequis
- Node >= 22.
- Sortie de paquet TypeScript ESM.
typeboxpour les schémas de configuration et de paramètres d’outils.openclaw >=2026.5.17, la première version d’OpenClaw qui exporteopenclaw/plugin-sdk/tool-plugin.- Une racine de paquet pouvant livrer
dist/,openclaw.plugin.jsonetpackage.json.
Le Plugin généré importe typebox à l’exécution ; gardez donc typebox dans
dependencies, pas seulement dans devDependencies.
Démarrage rapide
Créez un nouveau paquet de Plugin :
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm testL’échafaudage crée :
src/index.ts: une entréedefineToolPluginavec un outilecho.src/index.test.ts: un petit test de métadonnées.tsconfig.json: une sortie TypeScript NodeNext versdist/.package.json: scripts, dépendances d’exécution etopenclaw.extensions: ["./dist/index.js"].openclaw.plugin.json: métadonnées de manifeste générées pour l’outil initial.
Sortie de validation attendue :
Plugin stock-quotes is valid.Écrire un outil
defineToolPlugin prend l’identité du Plugin, un schéma de configuration facultatif et une
liste statique d’outils. Les types de paramètres et de configuration sont inférés à partir des schémas 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", }; }, }), ],});Les noms d’outils constituent l’API stable. Choisissez des noms uniques, en minuscules et suffisamment spécifiques pour éviter les collisions avec les outils du cœur ou d’autres Plugins.
Outils facultatifs et d’usine
Définissez optional: true lorsque les utilisateurs doivent explicitement autoriser l’outil avant qu’il
soit envoyé à un modèle :
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 écrit l’entrée de manifeste toolMetadata.<tool>.optional
correspondante, afin qu’OpenClaw puisse découvrir l’outil sans charger le code d’exécution du
Plugin.
Utilisez factory lorsqu’un outil a besoin du contexte d’outil d’exécution avant de pouvoir être
créé. L’usine garde les métadonnées statiques tout en laissant l’outil se désactiver pour une
exécution donnée, inspecter l’état du bac à sable ou lier des helpers d’exécution.
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); },});Les usines restent destinées à des noms d’outils fixes. Utilisez directement definePluginEntry lorsque
le Plugin calcule dynamiquement les noms d’outils ou combine des outils avec des hooks,
services, fournisseurs, commandes ou autres surfaces d’exécution.
Valeurs de retour
defineToolPlugin encapsule les valeurs de retour simples dans le format de résultat d’outil
d’OpenClaw :
- Retournez une chaîne lorsque le modèle doit voir exactement ce texte.
- Retournez une valeur compatible JSON lorsque vous voulez que le modèle voie du JSON formaté
et qu’OpenClaw conserve la valeur d’origine dans
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 }),});Utilisez un outil d’usine lorsque vous devez retourner un AgentToolResult personnalisé ou réutiliser
une implémentation api.registerTool existante. Utilisez definePluginEntry plutôt que
defineToolPlugin lorsque vous avez besoin d’outils entièrement dynamiques ou de capacités de Plugin
mixtes.
Configuration
configSchema est facultatif. Si vous l’omettez, OpenClaw utilise un schéma objet vide strict
et le manifeste généré inclut tout de même configSchema.
export default defineToolPlugin({ id: "no-config-tools", name: "No Config Tools", description: "Adds tools that do not need configuration.", tools: () => [],});Lorsque vous incluez configSchema, le deuxième argument de execute est typé à partir du
schéma :
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 lit la configuration du Plugin depuis l’entrée du Plugin dans la configuration du Gateway. Ne codez pas en dur de secrets dans le source ni dans les exemples de documentation. Utilisez la configuration, les variables d’environnement ou les SecretRefs selon le modèle de sécurité du Plugin.
Métadonnées générées
OpenClaw découvre les Plugins installés à partir de métadonnées froides. Il doit pouvoir lire
le manifeste du Plugin avant d’importer le code d’exécution du Plugin. defineToolPlugin
expose donc des métadonnées statiques, et openclaw plugins build écrit ces
métadonnées dans le paquet.
Exécutez le générateur après avoir modifié l’identifiant, le nom, la description, le schéma de configuration, l’activation ou les noms d’outils du Plugin :
npm run buildopenclaw plugins build --entry ./dist/index.jsPour un Plugin à un seul outil, le manifeste généré ressemble à ceci :
{ "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 est le contrat de découverte important. Il indique à OpenClaw quel
Plugin possède chaque outil sans charger l’exécution de chaque Plugin installé. Si le
manifeste est obsolète, l’outil peut être absent de la découverte ou le mauvais Plugin
peut être tenu responsable d’une erreur d’enregistrement.
Métadonnées de paquet
Pour le flux simple de Plugin d’outil, openclaw plugins build aligne
package.json sur l’unique entrée d’exécution sélectionnée :
{ "type": "module", "files": ["dist", "openclaw.plugin.json", "README.md"], "dependencies": { "typebox": "^1.1.38" }, "peerDependencies": { "openclaw": ">=2026.5.17" }, "openclaw": { "extensions": ["./dist/index.js"] }}Utilisez du JavaScript construit, comme ./dist/index.js, pour les paquets installés. Les entrées
source sont utiles lors du développement en espace de travail, mais les paquets publiés ne doivent pas
dépendre du chargement TypeScript à l’exécution.
Valider dans la CI
Utilisez plugins build --check pour faire échouer la CI lorsque les métadonnées générées sont obsolètes, sans
réécrire les fichiers :
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm testplugins validate vérifie que :
openclaw.plugin.jsonexiste et passe le chargeur de manifeste normal.- L’entrée actuelle exporte des métadonnées
defineToolPlugin. - Les champs de manifeste générés correspondent aux métadonnées de l’entrée.
contracts.toolscorrespond aux noms d’outils déclarés.package.jsonpointeopenclaw.extensionsvers l’entrée d’exécution sélectionnée.
Installer et inspecter localement
Depuis un autre checkout OpenClaw ou une CLI installée, installez le chemin du paquet :
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtimePour un smoke de paquet, empaquetez d’abord puis installez le tarball :
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --jsonAprès l’installation, démarrez ou redémarrez le Gateway et demandez à l’agent d’utiliser l’outil. Si vous déboguez la visibilité des outils, inspectez l’exécution du Plugin et le catalogue d’outils effectif avant de modifier le code.
Publier
Publiez via ClawHub lorsque le paquet est prêt :
clawhub package publish your-org/stock-quotes --dry-runclawhub package publish your-org/stock-quotesInstallez avec un localisateur ClawHub explicite :
openclaw plugins install clawhub:your-org/stock-quotesLes spécifications de paquet npm nues restent prises en charge pendant la transition de lancement, mais ClawHub est la surface de découverte et de distribution privilégiée pour les Plugins OpenClaw.
Dépannage
plugin entry not found: ./dist/index.js
Le fichier d’entrée sélectionné n’existe pas. Exécutez npm run build, puis relancez
openclaw plugins build --entry ./dist/index.js ou
openclaw plugins validate --entry ./dist/index.js.
plugin entry does not expose defineToolPlugin metadata
L’entrée n’a pas exporté une valeur créée par defineToolPlugin. Vérifiez que l’export par défaut du
module est le résultat de defineToolPlugin(...), ou passez la bonne
entrée avec --entry.
openclaw.plugin.json generated metadata is stale
Le manifeste ne correspond plus aux métadonnées de l’entrée. Exécutez :
npm run buildopenclaw plugins build --entry ./dist/index.jsValidez les modifications de openclaw.plugin.json et de package.json.
package.json openclaw.extensions must include ./dist/index.js
Les métadonnées du paquet pointent vers une autre entrée d’exécution. Exécutez
openclaw plugins build --entry ./dist/index.js afin que le générateur aligne les
métadonnées du paquet sur l’entrée que vous souhaitez livrer.
Cannot find package 'typebox'
Le Plugin construit importe typebox à l’exécution. Gardez typebox dans
dependencies, réinstallez les dépendances du paquet, reconstruisez et relancez la validation.
L’outil n’apparaît pas après l’installation
Vérifiez ces éléments dans l’ordre :
openclaw plugins inspect <plugin-id> --runtimeopenclaw plugins validate --root <plugin-root> --entry ./dist/index.jsopenclaw.plugin.jsoncontientcontracts.toolsavec les noms d’outils attendus.package.jsoncontientopenclaw.extensions: ["./dist/index.js"].- Le Gateway a été redémarré ou rechargé après l’installation du Plugin.