Plugins

Créer des plugins

Les plugins étendent OpenClaw avec de nouvelles capacités : canaux, fournisseurs de modèles, synthèse et reconnaissance vocales, transcription en temps réel, voix en temps réel, compréhension des médias, génération d’images, génération vidéo, récupération web, recherche web, outils d’agent ou toute combinaison de ces capacités.

Vous n’avez pas besoin d’ajouter votre plugin au dépôt OpenClaw. Publiez-le sur ClawHub et les utilisateurs l’installent avec openclaw plugins install clawhub:<package-name>. Les spécifications de paquet nues s’installent encore depuis npm pendant la transition de lancement.

Prérequis

  • Node >= 22 et un gestionnaire de paquets (npm ou pnpm)
  • Familiarité avec TypeScript (ESM)
  • Pour les plugins dans le dépôt : dépôt cloné et pnpm install effectué. Le développement de plugins depuis une copie de travail source est réservé à pnpm, car OpenClaw charge les plugins groupés depuis les paquets d’espace de travail extensions/*.

Quel type de plugin ?

Pour un plugin de canal dont l’installation n’est pas garantie au moment où l’intégration/la configuration s’exécute, utilisez createOptionalChannelSetupSurface(...) depuis openclaw/plugin-sdk/channel-setup. Il produit une paire adaptateur de configuration + assistant qui signale l’exigence d’installation et échoue de façon fermée lors des écritures réelles de configuration tant que le plugin n’est pas installé.

Démarrage rapide : plugin d’outil

Ce guide crée un plugin minimal qui enregistre un outil d’agent. Les plugins de canal et de fournisseur ont des guides dédiés liés ci-dessus.

  • Créer le paquet et le manifeste

    {
    "name": "@myorg/openclaw-my-plugin",
    "version": "1.0.0",
    "type": "module",
    "openclaw": {
      "extensions": ["./index.ts"],
      "compat": {
        "pluginApi": ">=2026.3.24-beta.2",
        "minGatewayVersion": "2026.3.24-beta.2"
      },
      "build": {
        "openclawVersion": "2026.3.24-beta.2",
        "pluginSdkVersion": "2026.3.24-beta.2"
      }
    }
    }
    
    {
    "id": "my-plugin",
    "name": "My Plugin",
    "description": "Adds a custom tool to OpenClaw",
    "contracts": {
      "tools": ["my_tool"]
    },
    "activation": {
      "onStartup": true
    },
    "configSchema": {
      "type": "object",
      "additionalProperties": false
    }
    }
    

    Chaque plugin a besoin d’un manifeste, même sans configuration. Les outils enregistrés à l’exécution doivent être listés dans contracts.tools afin qu’OpenClaw puisse découvrir le plugin propriétaire sans charger chaque environnement d’exécution de plugin. Les plugins doivent aussi déclarer activation.onStartup de manière intentionnelle. Cet exemple le définit à true. Consultez Manifeste pour le schéma complet. Les extraits canoniques de publication ClawHub se trouvent dans docs/snippets/plugin-publish/.

  • Écrire le point d’entrée

    // index.ts
    import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
    import { Type } from "@sinclair/typebox";
    
    export default definePluginEntry({
      id: "my-plugin",
      name: "My Plugin",
      description: "Adds a custom tool to OpenClaw",
      register(api) {
        api.registerTool({
          name: "my_tool",
          description: "Do a thing",
          parameters: Type.Object({ input: Type.String() }),
          async execute(_id, params) {
            return { content: [{ type: "text", text: `Got: ${params.input}` }] };
          },
        });
      },
    });
    

    definePluginEntry est destiné aux plugins qui ne sont pas des canaux. Pour les canaux, utilisez defineChannelPluginEntry - consultez Plugins de canal. Pour toutes les options de point d’entrée, consultez Points d’entrée.

  • Tester et publier

    Plugins externes : validez et publiez avec ClawHub, puis installez :

    clawhub package publish your-org/your-plugin --dry-run
    clawhub package publish your-org/your-plugin
    openclaw plugins install clawhub:@myorg/openclaw-my-plugin
    

    Les spécifications de paquet nues comme @myorg/openclaw-my-plugin s’installent depuis npm pendant la transition de lancement. Utilisez clawhub: lorsque vous voulez la résolution ClawHub.

    Plugins dans le dépôt : placez-les sous l’arborescence d’espace de travail des plugins groupés - ils sont découverts automatiquement.

    pnpm test -- <bundled-plugin-root>/my-plugin/
    
  • Capacités des plugins

    Un seul plugin peut enregistrer n’importe quel nombre de capacités via l’objet api :

    Capacité Méthode d’enregistrement Guide détaillé
    Inférence de texte (LLM) api.registerProvider(...) Plugins de fournisseur
    Backend d’inférence CLI api.registerCliBackend(...) Backends CLI
    Canal / messagerie api.registerChannel(...) Plugins de canal
    Voix (TTS/STT) api.registerSpeechProvider(...) Plugins de fournisseur
    Transcription en temps réel api.registerRealtimeTranscriptionProvider(...) Plugins de fournisseur
    Voix en temps réel api.registerRealtimeVoiceProvider(...) Plugins de fournisseur
    Compréhension des médias api.registerMediaUnderstandingProvider(...) Plugins de fournisseur
    Génération d’images api.registerImageGenerationProvider(...) Plugins de fournisseur
    Génération de musique api.registerMusicGenerationProvider(...) Plugins de fournisseur
    Génération vidéo api.registerVideoGenerationProvider(...) Plugins de fournisseur
    Récupération web api.registerWebFetchProvider(...) Plugins de fournisseur
    Recherche web api.registerWebSearchProvider(...) Plugins de fournisseur
    Middleware de résultat d’outil api.registerAgentToolResultMiddleware(...) Vue d’ensemble du SDK
    Outils d’agent api.registerTool(...) Ci-dessous
    Commandes personnalisées api.registerCommand(...) Points d’entrée
    Hooks de plugin api.on(...) Hooks de plugin
    Hooks d’événements internes api.registerHook(...) Points d’entrée
    Routes HTTP api.registerHttpRoute(...) Internes
    Sous-commandes CLI api.registerCli(...) Points d’entrée

    Pour l’API d’enregistrement complète, consultez Vue d’ensemble du SDK.

    Les plugins groupés peuvent utiliser api.registerAgentToolResultMiddleware(...) lorsqu’ils ont besoin de réécrire de manière asynchrone les résultats d’outils avant que le modèle voie la sortie. Déclarez les environnements d’exécution ciblés dans contracts.agentToolResultMiddleware, par exemple ["pi", "codex"]. Il s’agit d’un point d’extension de confiance pour les plugins groupés ; les plugins externes devraient préférer les hooks de plugin OpenClaw ordinaires, sauf si OpenClaw ajoute une politique de confiance explicite pour cette capacité.

    Si votre plugin enregistre des méthodes RPC Gateway personnalisées, conservez-les sous un préfixe propre au plugin. Les espaces de noms d’administration du cœur (config.*, exec.approvals.*, wizard.*, update.*) restent réservés et se résolvent toujours vers operator.admin, même si un plugin demande une portée plus étroite.

    Sémantique des gardes de hook à garder à l’esprit :

    • before_tool_call : { block: true } est terminal et arrête les gestionnaires de priorité inférieure.
    • before_tool_call : { block: false } est traité comme une absence de décision.
    • before_tool_call : { requireApproval: true } met en pause l’exécution de l’agent et demande l’approbation de l’utilisateur via la superposition d’approbation d’exécution, les boutons Telegram, les interactions Discord ou la commande /approve sur n’importe quel canal.
    • before_install : { block: true } est terminal et arrête les gestionnaires de priorité inférieure.
    • before_install : { block: false } est traité comme une absence de décision.
    • message_sending : { cancel: true } est terminal et arrête les gestionnaires de priorité inférieure.
    • message_sending : { cancel: false } est traité comme une absence de décision.
    • message_received : préférez le champ typé threadId lorsque vous avez besoin du routage entrant de fil/sujet. Conservez metadata pour les compléments propres au canal.
    • message_sending : préférez les champs de routage typés replyToId / threadId aux clés de métadonnées propres au canal.

    La commande /approve gère les approbations d’exécution et de plugin avec un repli borné : lorsqu’un identifiant d’approbation d’exécution est introuvable, OpenClaw réessaie le même identifiant via les approbations de plugin. Le transfert des approbations de plugin peut être configuré indépendamment via approvals.plugin dans la configuration.

    Si une plomberie d’approbation personnalisée doit détecter ce même cas de repli borné, préférez isApprovalNotFoundError depuis openclaw/plugin-sdk/error-runtime au lieu de faire correspondre manuellement les chaînes d’expiration d’approbation.

    Consultez Hooks de plugin pour des exemples et la référence des hooks.

    Enregistrer des outils d’agent

    Les outils sont des fonctions typées que le LLM peut appeler. Ils peuvent être requis (toujours disponibles) ou facultatifs (activation par l’utilisateur) :

    register(api) {
      // Required tool - always available
      api.registerTool({
        name: "my_tool",
        description: "Do a thing",
        parameters: Type.Object({ input: Type.String() }),
        async execute(_id, params) {
          return { content: [{ type: "text", text: params.input }] };
        },
      });
    
      // Optional tool - user must add to allowlist
      api.registerTool(
        {
          name: "workflow_tool",
          description: "Run a workflow",
          parameters: Type.Object({ pipeline: Type.String() }),
          async execute(_id, params) {
            return { content: [{ type: "text", text: params.pipeline }] };
          },
        },
        { optional: true },
      );
    }
    

    Chaque outil enregistré avec api.registerTool(...) doit aussi être déclaré dans le manifeste du plugin :

    {
      "contracts": {
        "tools": ["my_tool", "workflow_tool"]
      },
      "toolMetadata": {
        "workflow_tool": {
          "optional": true
        }
      }
    }
    

    OpenClaw capture et met en cache le descripteur validé depuis l’outil enregistré, afin que les plugins ne dupliquent pas les données description ou de schéma dans le manifeste. Le contrat du manifeste ne déclare que la propriété et la découverte ; l’exécution appelle toujours l’implémentation active de l’outil enregistré. Définissez toolMetadata.<tool>.optional: true pour les outils enregistrés avec api.registerTool(..., { optional: true }) afin qu’OpenClaw puisse éviter de charger ce runtime de plugin tant que l’outil n’est pas explicitement allowlisted.

    Les utilisateurs activent les outils optionnels dans la configuration :

    {
      tools: { allow: ["workflow_tool"] },
    }
    
    • Les noms d’outils ne doivent pas entrer en conflit avec les outils du cœur (les conflits sont ignorés)
    • Les outils avec des objets d’enregistrement mal formés, y compris ceux auxquels il manque parameters, sont ignorés et signalés dans les diagnostics du plugin au lieu d’interrompre les exécutions d’agents
    • Utilisez optional: true pour les outils avec des effets de bord ou des exigences binaires supplémentaires
    • Les utilisateurs peuvent activer tous les outils d’un plugin en ajoutant l’id du plugin à tools.allow

    Enregistrement des commandes CLI

    Les plugins peuvent ajouter des groupes de commandes racine openclaw avec api.registerCli. Fournissez des descriptors pour chaque racine de commande de premier niveau afin qu’OpenClaw puisse afficher et router la commande sans charger avidement chaque runtime de plugin.

    register(api) {
      api.registerCli(
        ({ program }) => {
          const demo = program
            .command("demo-plugin")
            .description("Run demo plugin commands");
    
          demo
            .command("ping")
            .description("Check that the plugin CLI is executable")
            .action(() => {
              console.log("demo-plugin:pong");
            });
        },
        {
          descriptors: [
            {
              name: "demo-plugin",
              description: "Run demo plugin commands",
              hasSubcommands: true,
            },
          ],
        },
      );
    }
    

    Après l’installation, vérifiez l’enregistrement du runtime et exécutez la commande :

    openclaw plugins inspect demo-plugin --runtime --json
    openclaw demo-plugin ping
    

    Conventions d’importation

    Importez toujours depuis des chemins ciblés openclaw/plugin-sdk/<subpath> :

    
    
    // Wrong: monolithic root (deprecated, will be removed)
    
    

    Pour la référence complète des sous-chemins, consultez Vue d’ensemble du SDK.

    Dans votre plugin, utilisez des fichiers barrel locaux (api.ts, runtime-api.ts) pour les imports internes - n’importez jamais votre propre plugin via son chemin SDK.

    Pour les plugins de fournisseurs, conservez les helpers propres au fournisseur dans ces barrels à la racine du paquet, sauf si le point d’intégration est réellement générique. Exemples groupés actuels :

    • Anthropic : wrappers de flux Claude et helpers service_tier / bêta
    • OpenAI : builders de fournisseur, helpers de modèle par défaut, fournisseurs temps réel
    • OpenRouter : builder de fournisseur plus helpers d’onboarding/configuration

    Si un helper n’est utile qu’à l’intérieur d’un seul paquet de fournisseur groupé, conservez-le sur ce point d’intégration à la racine du paquet au lieu de le promouvoir dans openclaw/plugin-sdk/*.

    Certains points d’intégration de helpers générés openclaw/plugin-sdk/<bundled-id> existent encore pour la maintenance des plugins groupés lorsqu’ils ont un usage propriétaire suivi. Traitez-les comme des surfaces réservées, et non comme le modèle par défaut pour les nouveaux plugins tiers.

    Liste de vérification avant soumission

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s package.json contient les métadonnées openclaw correctes OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s Le manifeste openclaw.plugin.json est présent et valide OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s Le point d’entrée utilise defineChannelPluginEntry ou definePluginEntry OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s Tous les imports utilisent des chemins ciblés plugin-sdk/<subpath> OPENCLAW_DOCS_MARKER:calloutClose: