Building plugins
ããŒã« Plugin
ããŒã« Plugin ã¯ããã£ãã«ãã¢ãã«ãããã€ããŒãããã¯ããµãŒãã¹ãã»ããã¢ããããã¯ãšã³ãã远å ããã«ããšãŒãžã§ã³ãããåŒã³åºããããŒã«ã OpenClaw ã«è¿œå ããŸããPlugin ãåºå®ã®ããŒã«äžèŠ§ãææããã©ã³ã¿ã€ã ã³ãŒããèªã¿èŸŒãŸãªããŠããããã®ããŒã«ãçºèŠå¯èœã«ä¿ã€ãããã§ã¹ãã¡ã¿ããŒã¿ã OpenClaw ã«çæããããå Žåã¯ãdefineToolPlugin ã䜿çšããŸãã
æšå¥šãããŒã¯æ¬¡ã®ãšããã§ãã
openclaw plugins initã§ããã±ãŒãžãã¹ãã£ãã©ãŒã«ãããŸããdefineToolPluginã§ããŒã«ãèšè¿°ããŸãã- JavaScript ããã«ãããŸãã
openclaw plugins buildã§openclaw.plugin.jsonãšpackage.jsonã®ã¡ã¿ããŒã¿ãçæããŸãã- å ¬éãŸãã¯ã€ã³ã¹ããŒã«ã®åã«ãçæãããã¡ã¿ããŒã¿ãæ€èšŒããŸãã
ãããã€ããŒããã£ãã«ãããã¯ããµãŒãã¹ããŸãã¯è€åã±ã€ãããªãã£ã® Plugin ã§ã¯ã代ããã« Plugin ã®æ§ç¯ããã£ãã« Pluginã ãŸã㯠ãããã€ã㌠Plugin ããå§ããŸãã
èŠä»¶
- Node >= 22ã
- TypeScript ESM ããã±ãŒãžåºåã
- èšå®ãšããŒã«ãã©ã¡ãŒã¿ãŒã®ã¹ããŒãã«ã¯
typeboxã openclaw >=2026.5.17ãopenclaw/plugin-sdk/tool-pluginããšã¯ã¹ããŒãããæåã® OpenClaw ããŒãžã§ã³ã§ããdist/ãopenclaw.plugin.jsonãpackage.jsonãé åžã§ããããã±ãŒãžã«ãŒãã
çæããã Plugin ã¯ã©ã³ã¿ã€ã ã§ typebox ãã€ã³ããŒããããããtypebox 㯠devDependencies ã ãã§ãªã dependencies ã«ä¿æããŠãã ããã
ã¯ã€ãã¯ã¹ã¿ãŒã
æ°ãã Plugin ããã±ãŒãžãäœæããŸãã
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm testã¹ãã£ãã©ãŒã«ãã¯æ¬¡ãäœæããŸãã
src/index.ts:echoããŒã«ãæã€defineToolPluginãšã³ããªãsrc/index.test.ts: å°ããªã¡ã¿ããŒã¿ãã¹ããtsconfig.json:dist/ãžã® NodeNext TypeScript åºåãpackage.json: ã¹ã¯ãªãããã©ã³ã¿ã€ã äŸåé¢ä¿ãããã³openclaw.extensions: ["./dist/index.js"]ãopenclaw.plugin.json: åæããŒã«çšã«çæããããããã§ã¹ãã¡ã¿ããŒã¿ã
æåŸ ãããæ€èšŒåºå:
Plugin stock-quotes is valid.ããŒã«ãæžã
defineToolPlugin ã¯ãPlugin ã®è奿
å ±ãä»»æã®èšå®ã¹ããŒããããã³éçãªããŒã«äžèЧãåãåããŸãããã©ã¡ãŒã¿ãŒåãšèšå®å㯠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", }; }, }), ],});ããŒã«åã¯å®å®ãã API ã§ããã³ã¢ããŒã«ãä»ã® Plugin ãšè¡çªããªããããäžæã§å°æåããã€ååã«å ·äœçãªååãéžã³ãŸãã
ä»»æããŒã«ãšãã¡ã¯ããªãŒããŒã«
ã¢ãã«ãžéä¿¡ããåã«ããŠãŒã¶ãŒããã®ããŒã«ãæç€ºçã«èš±å¯ãªã¹ããžè¿œå ããå¿
èŠãããå Žåã¯ãoptional: true ãèšå®ããŸãã
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 ã¯å¯Ÿå¿ãã toolMetadata.<tool>.optional ãããã§ã¹ããšã³ããªãæžã蟌ããããOpenClaw 㯠Plugin ã©ã³ã¿ã€ã ã³ãŒããèªã¿èŸŒãŸãã«ããŒã«ãçºèŠã§ããŸãã
ããŒã«ãäœæããåã«ã©ã³ã¿ã€ã ããŒã«ã³ã³ããã¹ããå¿
èŠãªå Žåã¯ãfactory ã䜿çšããŸãããã¡ã¯ããªãŒã¯ã¡ã¿ããŒã¿ãéçã«ä¿ã¡ãªãããç¹å®ã®å®è¡ã§ããŒã«ããªããã¢ãŠããããããµã³ãããã¯ã¹ç¶æ
ãæ€æ»ããããã©ã³ã¿ã€ã ãã«ããŒããã€ã³ããããã§ããŸãã
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); },});ãã¡ã¯ããªãŒãåºå®ãããããŒã«ååãã§ããPlugin ãããŒã«åãåçã«èšç®ããå ŽåããŸãã¯ããŒã«ãããã¯ããµãŒãã¹ããããã€ããŒãã³ãã³ãããã®ä»ã®ã©ã³ã¿ã€ã ãµãŒãã§ã¹ãšçµã¿åãããå Žåã¯ãdefinePluginEntry ãçŽæ¥äœ¿çšããŸãã
æ»ãå€
defineToolPlugin ã¯ãã¬ãŒã³ãªæ»ãå€ã OpenClaw ã®ããŒã«çµæåœ¢åŒã«ã©ããããŸãã
- ã¢ãã«ã«ãã®æ£ç¢ºãªããã¹ããèŠãããå Žåã¯ãæååãè¿ããŸãã
- ã¢ãã«ã«æŽåœ¢æžã¿ JSON ãèŠããOpenClaw ã«ã¯å
ã®å€ã
detailsã«ä¿æããããå Žåã¯ãJSON äºæã®å€ãè¿ããŸãã
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 }),});ã«ã¹ã¿ã ã® AgentToolResult ãè¿ãå¿
èŠãããå ŽåããŸãã¯æ¢åã® api.registerTool å®è£
ãåå©çšããå¿
èŠãããå Žåã¯ããã¡ã¯ããªãŒããŒã«ã䜿çšããŸããå®å
šã«åçãªããŒã«ãŸãã¯è€å Plugin ã±ã€ãããªãã£ãå¿
èŠãªå Žåã¯ãdefineToolPlugin ã§ã¯ãªã definePluginEntry ã䜿çšããŸãã
èšå®
configSchema ã¯ä»»æã§ããçç¥ããå ŽåãOpenClaw ã¯å³å¯ãªç©ºãªããžã§ã¯ãã¹ããŒãã䜿çšããçæããããããã§ã¹ãã«ã configSchema ãå«ãŸããŸãã
export default defineToolPlugin({ id: "no-config-tools", name: "No Config Tools", description: "Adds tools that do not need configuration.", tools: () => [],});configSchema ãå«ãããšã2 çªç®ã® execute åŒæ°ã¯ã¹ããŒãããåä»ããããŸãã
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 㯠Gateway èšå®å ã® Plugin ãšã³ããªãã Plugin èšå®ãèªã¿åããŸãããœãŒã¹ãããã¥ã¡ã³ãäŸã«ã·ãŒã¯ã¬ãããããŒãã³ãŒãããªãã§ãã ãããPlugin ã®ã»ãã¥ãªãã£ã¢ãã«ã«åŸã£ãŠãèšå®ãç°å¢å€æ°ããŸã㯠SecretRefs ã䜿çšããŸãã
çæãããã¡ã¿ããŒã¿
OpenClaw ã¯ã³ãŒã«ãã¡ã¿ããŒã¿ããã€ã³ã¹ããŒã«æžã¿ Plugin ãçºèŠããŸããPlugin ã©ã³ã¿ã€ã ã³ãŒããã€ã³ããŒãããåã«ãPlugin ãããã§ã¹ããèªã¿åããå¿
èŠããããŸãããã®ãã defineToolPlugin ã¯éçã¡ã¿ããŒã¿ãå
¬éããopenclaw plugins build ã¯ãã®ã¡ã¿ããŒã¿ãããã±ãŒãžãžæžã蟌ã¿ãŸãã
Plugin IDãååã説æãèšå®ã¹ããŒããã¢ã¯ãã£ããŒã·ã§ã³ããŸãã¯ããŒã«åã倿ŽããåŸã¯ããžã§ãã¬ãŒã¿ãŒãå®è¡ããŸãã
npm run buildopenclaw plugins build --entry ./dist/index.js1 ããŒã«ã® Plugin ã§ã¯ãçæããããããã§ã¹ãã¯æ¬¡ã®ããã«ãªããŸãã
{ "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 ã¯éèŠãªçºèŠã³ã³ãã©ã¯ãã§ããããã¯ãã€ã³ã¹ããŒã«æžã¿ã®ãã¹ãŠã® Plugin ã©ã³ã¿ã€ã ãèªã¿èŸŒãŸãã«ãã©ã® Plugin ãåããŒã«ãææããŠãããã OpenClaw ã«äŒããŸãããããã§ã¹ããå€ãå ŽåãçºèŠçµæããããŒã«ãæ¬ èœããããç»é²ãšã©ãŒã«ã€ããŠèª€ã£ã Plugin ãåå ãšèŠãªããããããå¯èœæ§ããããŸãã
ããã±ãŒãžã¡ã¿ããŒã¿
ã·ã³ãã«ãªããŒã« Plugin ã¯ãŒã¯ãããŒã§ã¯ãopenclaw plugins build 㯠package.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"] }}ã€ã³ã¹ããŒã«æžã¿ããã±ãŒãžã§ã¯ã./dist/index.js ã®ãããªãã«ãæžã¿ JavaScript ã䜿çšããŸãããœãŒã¹ãšã³ããªã¯ã¯ãŒã¯ã¹ããŒã¹éçºã§ã¯äŸ¿å©ã§ãããå
¬éããã±ãŒãžã¯ TypeScript ã©ã³ã¿ã€ã èªã¿èŸŒã¿ã«äŸåãã¹ãã§ã¯ãããŸããã
CI ã§æ€èšŒãã
çæãããã¡ã¿ããŒã¿ãå€ãå Žåã«ãã¡ã€ã«ãæžãæãã CI ã倱æãããã«ã¯ãplugins build --check ã䜿çšããŸãã
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm testplugins validate ã¯æ¬¡ã確èªããŸãã
openclaw.plugin.jsonãååšããéåžžã®ãããã§ã¹ãããŒããŒã«åæ Œããããšã- çŸåšã®ãšã³ããªã
defineToolPluginã¡ã¿ããŒã¿ããšã¯ã¹ããŒãããŠããããšã - çæããããããã§ã¹ããã£ãŒã«ãããšã³ããªã¡ã¿ããŒã¿ãšäžèŽããããšã
contracts.toolsã宣èšãããããŒã«åãšäžèŽããããšãpackage.jsonãopenclaw.extensionsã§éžæãããã©ã³ã¿ã€ã ãšã³ããªãæããŠããããšã
ããŒã«ã«ã§ã€ã³ã¹ããŒã«ããŠèª¿æ»ãã
å¥ã® OpenClaw ãã§ãã¯ã¢ãŠããŸãã¯ã€ã³ã¹ããŒã«æžã¿ CLI ãããããã±ãŒãžãã¹ãã€ã³ã¹ããŒã«ããŸãã
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtimeããã±ãŒãžåãããã¹ã¢ãŒã¯ã§ã¯ãå ã«ããã¯ã㊠tarball ãã€ã³ã¹ããŒã«ããŸãã
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --jsonã€ã³ã¹ããŒã«åŸãGateway ãèµ·åãŸãã¯åèµ·åãããšãŒãžã§ã³ãã«ããŒã«ã䜿ãããäŸé ŒããŸããããŒã«ã®å¯èŠæ§ããããã°ããŠããå Žåã¯ãã³ãŒãã倿Žããåã« Plugin ã©ã³ã¿ã€ã ãšæå¹ãªããŒã«ã«ã¿ãã°ã調æ»ããŸãã
å ¬é
ããã±ãŒãžã®æºåãã§ããã ClawHub çµç±ã§å ¬éããŸãã
clawhub package publish your-org/stock-quotes --dry-runclawhub package publish your-org/stock-quotesæç€ºç㪠ClawHub ãã±ãŒã¿ãŒã§ã€ã³ã¹ããŒã«ããŸãã
openclaw plugins install clawhub:your-org/stock-quotesããŒã³ãç§»è¡äžã¯çŽ ã® npm ããã±ãŒãžæå®ãåŒãç¶ããµããŒããããŸãããOpenClaw Plugin ã®çºèŠãšé åžã®ãµãŒãã§ã¹ãšããŠã¯ ClawHub ãæšå¥šã§ãã
ãã©ãã«ã·ã¥ãŒãã£ã³ã°
plugin entry not found: ./dist/index.js
éžæããããšã³ããªãã¡ã€ã«ãååšããŸãããnpm run build ãå®è¡ããŠãããopenclaw plugins build --entry ./dist/index.js ãŸã㯠openclaw plugins validate --entry ./dist/index.js ãåå®è¡ããŸãã
plugin entry does not expose defineToolPlugin metadata
ãšã³ããªã defineToolPlugin ã§äœæãããå€ããšã¯ã¹ããŒãããŠããŸãããã¢ãžã¥ãŒã«ã®ããã©ã«ããšã¯ã¹ããŒãã defineToolPlugin(...) ã®çµæã§ããããšã確èªãããã--entry ã§æ£ãããšã³ããªãæž¡ããŸãã
openclaw.plugin.json generated metadata is stale
ãããã§ã¹ãããšã³ããªã¡ã¿ããŒã¿ãšäžèŽããªããªã£ãŠããŸããæ¬¡ãå®è¡ããŸãã
npm run buildopenclaw plugins build --entry ./dist/index.jsopenclaw.plugin.json ãš package.json ã®äž¡æ¹ã®å€æŽãã³ãããããŸãã
package.json openclaw.extensions must include ./dist/index.js
ããã±ãŒãžã¡ã¿ããŒã¿ãå¥ã®ã©ã³ã¿ã€ã ãšã³ããªãæããŠããŸãããžã§ãã¬ãŒã¿ãŒãé
åžäºå®ã®ãšã³ããªã«ããã±ãŒãžã¡ã¿ããŒã¿ãåããããããopenclaw plugins build --entry ./dist/index.js ãå®è¡ããŸãã
Cannot find package 'typebox'
ãã«ãæžã¿ Plugin ã¯ã©ã³ã¿ã€ã ã§ typebox ãã€ã³ããŒãããŸããtypebox ã dependencies ã«ä¿æããããã±ãŒãžäŸåé¢ä¿ãåã€ã³ã¹ããŒã«ããŠãåãã«ãããæ€èšŒãåå®è¡ããŸãã
ã€ã³ã¹ããŒã«åŸã«ããŒã«ã衚瀺ãããªã
次ãé çªã«ç¢ºèªããŸãã
openclaw plugins inspect <plugin-id> --runtimeopenclaw plugins validate --root <plugin-root> --entry ./dist/index.jsopenclaw.plugin.jsonã®contracts.toolsã«æåŸ ããããŒã«åãå«ãŸããŠããããšãpackage.jsonã«openclaw.extensions: ["./dist/index.js"]ãããããšã- Plugin ã®ã€ã³ã¹ããŒã«åŸã« Gateway ãåèµ·åãŸãã¯ãªããŒããããŠããããšã