diff --git a/docs/plugins/manifest.md b/docs/plugins/manifest.md index 5de3abcc661d..31f6f129cf10 100644 --- a/docs/plugins/manifest.md +++ b/docs/plugins/manifest.md @@ -191,6 +191,7 @@ or npm install metadata. Those belong in your plugin code and `package.json`. | `skills` | No | `string[]` | Skill directories to load, relative to the plugin root. | | `name` | No | `string` | Human-readable plugin name. | | `description` | No | `string` | Short summary shown in plugin surfaces. | +| `icon` | No | `string` | HTTPS image URL for marketplace/catalog cards. ClawHub accepts any valid `https://` URL and falls back to the default plugin icon when this is omitted or invalid. | | `version` | No | `string` | Informational plugin version. | | `uiHints` | No | `Record` | UI labels, placeholders, and sensitivity hints for config fields. | diff --git a/extensions/alibaba/openclaw.plugin.json b/extensions/alibaba/openclaw.plugin.json index ace13cee4a8c..ea5793f6ea2d 100644 --- a/extensions/alibaba/openclaw.plugin.json +++ b/extensions/alibaba/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "alibaba", + "icon": "https://cdn.simpleicons.org/alibabacloud/111111", "activation": { "onStartup": false }, diff --git a/extensions/anthropic-vertex/openclaw.plugin.json b/extensions/anthropic-vertex/openclaw.plugin.json index f9aba808b263..6f8cabd474c5 100644 --- a/extensions/anthropic-vertex/openclaw.plugin.json +++ b/extensions/anthropic-vertex/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "anthropic-vertex", "name": "Anthropic Vertex", "description": "OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI.", + "icon": "https://cdn.simpleicons.org/anthropic/111111", "activation": { "onStartup": false }, diff --git a/extensions/anthropic/openclaw.plugin.json b/extensions/anthropic/openclaw.plugin.json index aba2194aef7f..7ca036c5566f 100644 --- a/extensions/anthropic/openclaw.plugin.json +++ b/extensions/anthropic/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "anthropic", + "icon": "https://cdn.simpleicons.org/anthropic/111111", "activation": { "onStartup": false }, diff --git a/extensions/brave/openclaw.plugin.json b/extensions/brave/openclaw.plugin.json index 915a60c0fc01..b6bd6aa7634d 100644 --- a/extensions/brave/openclaw.plugin.json +++ b/extensions/brave/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "brave", "name": "Brave", "description": "OpenClaw Brave Search provider plugin for web search.", + "icon": "https://cdn.simpleicons.org/brave/111111", "activation": { "onStartup": false }, diff --git a/extensions/cloudflare-ai-gateway/openclaw.plugin.json b/extensions/cloudflare-ai-gateway/openclaw.plugin.json index e57b1f761e7b..f3050706537f 100644 --- a/extensions/cloudflare-ai-gateway/openclaw.plugin.json +++ b/extensions/cloudflare-ai-gateway/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "cloudflare-ai-gateway", + "icon": "https://cdn.simpleicons.org/cloudflare/111111", "activation": { "onStartup": false }, diff --git a/extensions/copilot-proxy/openclaw.plugin.json b/extensions/copilot-proxy/openclaw.plugin.json index 398bdcad3726..a1c8b52a3aa5 100644 --- a/extensions/copilot-proxy/openclaw.plugin.json +++ b/extensions/copilot-proxy/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "copilot-proxy", + "icon": "https://cdn.simpleicons.org/githubcopilot/111111", "activation": { "onStartup": false }, diff --git a/extensions/copilot/openclaw.plugin.json b/extensions/copilot/openclaw.plugin.json index 450b5c48dfa0..84e2318019d5 100644 --- a/extensions/copilot/openclaw.plugin.json +++ b/extensions/copilot/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "copilot", "name": "GitHub Copilot agent runtime", "description": "Registers the GitHub Copilot agent runtime.", + "icon": "https://cdn.simpleicons.org/githubcopilot/111111", "version": "2026.6.2", "activation": { "onStartup": false, diff --git a/extensions/deepgram/openclaw.plugin.json b/extensions/deepgram/openclaw.plugin.json index 9ede70b10eb7..8054e180b8ab 100644 --- a/extensions/deepgram/openclaw.plugin.json +++ b/extensions/deepgram/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "deepgram", + "icon": "https://cdn.simpleicons.org/deepgram/111111", "activation": { "onStartup": false }, diff --git a/extensions/deepseek/openclaw.plugin.json b/extensions/deepseek/openclaw.plugin.json index 3813d9ccc429..df48a86f10eb 100644 --- a/extensions/deepseek/openclaw.plugin.json +++ b/extensions/deepseek/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "deepseek", + "icon": "https://cdn.simpleicons.org/deepseek/111111", "activation": { "onStartup": false }, diff --git a/extensions/discord/openclaw.plugin.json b/extensions/discord/openclaw.plugin.json index 8b7a9a9c48e5..3a6e727b4a28 100644 --- a/extensions/discord/openclaw.plugin.json +++ b/extensions/discord/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "discord", "name": "Discord", "description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.", + "icon": "https://cdn.simpleicons.org/discord/111111", "skills": ["./skills"], "activation": { "onStartup": false diff --git a/extensions/duckduckgo/openclaw.plugin.json b/extensions/duckduckgo/openclaw.plugin.json index afd2335929be..26d7374f60cd 100644 --- a/extensions/duckduckgo/openclaw.plugin.json +++ b/extensions/duckduckgo/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "duckduckgo", + "icon": "https://cdn.simpleicons.org/duckduckgo/111111", "activation": { "onStartup": false }, diff --git a/extensions/elevenlabs/openclaw.plugin.json b/extensions/elevenlabs/openclaw.plugin.json index f4207de6b1d4..181f85d5b2be 100644 --- a/extensions/elevenlabs/openclaw.plugin.json +++ b/extensions/elevenlabs/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "elevenlabs", + "icon": "https://cdn.simpleicons.org/elevenlabs/111111", "activation": { "onStartup": false }, diff --git a/extensions/google-meet/openclaw.plugin.json b/extensions/google-meet/openclaw.plugin.json index 083d0c604b22..0dd334ea8b41 100644 --- a/extensions/google-meet/openclaw.plugin.json +++ b/extensions/google-meet/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "google-meet", "name": "Google Meet", "description": "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.", + "icon": "https://cdn.simpleicons.org/googlemeet/111111", "enabledByDefault": false, "commandAliases": [{ "name": "googlemeet" }], "activation": { diff --git a/extensions/google/openclaw.plugin.json b/extensions/google/openclaw.plugin.json index 9d673c6162a1..8c8686c55aa7 100644 --- a/extensions/google/openclaw.plugin.json +++ b/extensions/google/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "google", + "icon": "https://cdn.simpleicons.org/google/111111", "activation": { "onStartup": false }, diff --git a/extensions/googlechat/openclaw.plugin.json b/extensions/googlechat/openclaw.plugin.json index 5d294cf7820f..919608c0a71e 100644 --- a/extensions/googlechat/openclaw.plugin.json +++ b/extensions/googlechat/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "googlechat", "name": "Google Chat", "description": "OpenClaw Google Chat channel plugin for spaces and direct messages.", + "icon": "https://cdn.simpleicons.org/googlechat/111111", "activation": { "onStartup": false }, diff --git a/extensions/huggingface/openclaw.plugin.json b/extensions/huggingface/openclaw.plugin.json index f0004b68b339..614ee1b22029 100644 --- a/extensions/huggingface/openclaw.plugin.json +++ b/extensions/huggingface/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "huggingface", + "icon": "https://cdn.simpleicons.org/huggingface/111111", "activation": { "onStartup": false }, diff --git a/extensions/imessage/openclaw.plugin.json b/extensions/imessage/openclaw.plugin.json index 302f9483d358..e4e74ef18819 100644 --- a/extensions/imessage/openclaw.plugin.json +++ b/extensions/imessage/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "imessage", + "icon": "https://cdn.simpleicons.org/imessage/111111", "activation": { "onStartup": false }, diff --git a/extensions/line/openclaw.plugin.json b/extensions/line/openclaw.plugin.json index b00c7d20bb0a..240c43670f70 100644 --- a/extensions/line/openclaw.plugin.json +++ b/extensions/line/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "line", "name": "LINE", "description": "OpenClaw LINE channel plugin for LINE Bot API chats.", + "icon": "https://cdn.simpleicons.org/line/111111", "activation": { "onStartup": false }, diff --git a/extensions/lmstudio/openclaw.plugin.json b/extensions/lmstudio/openclaw.plugin.json index 63f64ea6a0ef..c485f6609447 100644 --- a/extensions/lmstudio/openclaw.plugin.json +++ b/extensions/lmstudio/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "lmstudio", + "icon": "https://cdn.simpleicons.org/lmstudio/111111", "activation": { "onStartup": false }, diff --git a/extensions/matrix/openclaw.plugin.json b/extensions/matrix/openclaw.plugin.json index 2bcdfae5db2b..4253689a4ee3 100644 --- a/extensions/matrix/openclaw.plugin.json +++ b/extensions/matrix/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "matrix", "name": "Matrix", "description": "OpenClaw Matrix channel plugin for rooms and direct messages.", + "icon": "https://cdn.simpleicons.org/matrix/111111", "commandAliases": [{ "name": "matrix" }], "activation": { "onStartup": false, diff --git a/extensions/mattermost/openclaw.plugin.json b/extensions/mattermost/openclaw.plugin.json index 725d784f8b52..3b751718d36b 100644 --- a/extensions/mattermost/openclaw.plugin.json +++ b/extensions/mattermost/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "mattermost", + "icon": "https://cdn.simpleicons.org/mattermost/111111", "activation": { "onStartup": false }, diff --git a/extensions/minimax/openclaw.plugin.json b/extensions/minimax/openclaw.plugin.json index f1965b3247db..a0fd12f34e02 100644 --- a/extensions/minimax/openclaw.plugin.json +++ b/extensions/minimax/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "minimax", + "icon": "https://cdn.simpleicons.org/minimax/111111", "activation": { "onStartup": false }, diff --git a/extensions/mistral/openclaw.plugin.json b/extensions/mistral/openclaw.plugin.json index b216d6051324..718d044d09a7 100644 --- a/extensions/mistral/openclaw.plugin.json +++ b/extensions/mistral/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "mistral", + "icon": "https://cdn.simpleicons.org/mistralai/111111", "activation": { "onStartup": false }, diff --git a/extensions/nextcloud-talk/openclaw.plugin.json b/extensions/nextcloud-talk/openclaw.plugin.json index 751f3faf5aa7..1b645df0e66c 100644 --- a/extensions/nextcloud-talk/openclaw.plugin.json +++ b/extensions/nextcloud-talk/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "nextcloud-talk", "name": "Nextcloud Talk", "description": "OpenClaw Nextcloud Talk channel plugin for conversations.", + "icon": "https://cdn.simpleicons.org/nextcloud/111111", "activation": { "onStartup": false }, diff --git a/extensions/nvidia/openclaw.plugin.json b/extensions/nvidia/openclaw.plugin.json index be01e77f4957..240b6b9fae57 100644 --- a/extensions/nvidia/openclaw.plugin.json +++ b/extensions/nvidia/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "nvidia", + "icon": "https://cdn.simpleicons.org/nvidia/111111", "activation": { "onStartup": false }, diff --git a/extensions/ollama/openclaw.plugin.json b/extensions/ollama/openclaw.plugin.json index 260539c91978..33ae833c8e12 100644 --- a/extensions/ollama/openclaw.plugin.json +++ b/extensions/ollama/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "ollama", + "icon": "https://cdn.simpleicons.org/ollama/111111", "activation": { "onStartup": false }, diff --git a/extensions/opencode-go/openclaw.plugin.json b/extensions/opencode-go/openclaw.plugin.json index cd67eb5c3e34..fb12aae9881b 100644 --- a/extensions/opencode-go/openclaw.plugin.json +++ b/extensions/opencode-go/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "opencode-go", + "icon": "https://cdn.simpleicons.org/opencode/111111", "activation": { "onStartup": false }, diff --git a/extensions/opencode/openclaw.plugin.json b/extensions/opencode/openclaw.plugin.json index 0da1c98df6bd..9e792d296caf 100644 --- a/extensions/opencode/openclaw.plugin.json +++ b/extensions/opencode/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "opencode", + "icon": "https://cdn.simpleicons.org/opencode/111111", "activation": { "onStartup": false }, diff --git a/extensions/openrouter/openclaw.plugin.json b/extensions/openrouter/openclaw.plugin.json index c8f0afeba1c8..df47aae8b5f2 100644 --- a/extensions/openrouter/openclaw.plugin.json +++ b/extensions/openrouter/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "openrouter", + "icon": "https://cdn.simpleicons.org/openrouter/111111", "activation": { "onStartup": false }, diff --git a/extensions/perplexity/openclaw.plugin.json b/extensions/perplexity/openclaw.plugin.json index 77048fcdcbd1..2b75be5f8962 100644 --- a/extensions/perplexity/openclaw.plugin.json +++ b/extensions/perplexity/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "perplexity", + "icon": "https://cdn.simpleicons.org/perplexity/111111", "activation": { "onStartup": false }, diff --git a/extensions/qianfan/openclaw.plugin.json b/extensions/qianfan/openclaw.plugin.json index 9d5993b959a3..12d517d42404 100644 --- a/extensions/qianfan/openclaw.plugin.json +++ b/extensions/qianfan/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "qianfan", + "icon": "https://cdn.simpleicons.org/baidu/111111", "activation": { "onStartup": false }, diff --git a/extensions/qqbot/openclaw.plugin.json b/extensions/qqbot/openclaw.plugin.json index 3c5e16ea80e7..520c16e892b3 100644 --- a/extensions/qqbot/openclaw.plugin.json +++ b/extensions/qqbot/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "qqbot", "name": "QQ Bot", "description": "OpenClaw QQ Bot channel plugin for group and direct-message workflows.", + "icon": "https://cdn.simpleicons.org/qq/111111", "activation": { "onStartup": false }, diff --git a/extensions/qwen/openclaw.plugin.json b/extensions/qwen/openclaw.plugin.json index 99979da71669..aedc8aaee39a 100644 --- a/extensions/qwen/openclaw.plugin.json +++ b/extensions/qwen/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "qwen", + "icon": "https://cdn.simpleicons.org/qwen/111111", "activation": { "onStartup": false }, diff --git a/extensions/searxng/openclaw.plugin.json b/extensions/searxng/openclaw.plugin.json index a557a8686640..ae4ca92b9d11 100644 --- a/extensions/searxng/openclaw.plugin.json +++ b/extensions/searxng/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "searxng", + "icon": "https://cdn.simpleicons.org/searxng/111111", "activation": { "onStartup": false }, diff --git a/extensions/signal/openclaw.plugin.json b/extensions/signal/openclaw.plugin.json index 6ba18fc8d882..03f9e2b0ba02 100644 --- a/extensions/signal/openclaw.plugin.json +++ b/extensions/signal/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "signal", + "icon": "https://cdn.simpleicons.org/signal/111111", "activation": { "onStartup": false }, diff --git a/extensions/synology-chat/openclaw.plugin.json b/extensions/synology-chat/openclaw.plugin.json index c23a4a6ac290..bcb3c61daa9e 100644 --- a/extensions/synology-chat/openclaw.plugin.json +++ b/extensions/synology-chat/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "synology-chat", "name": "Synology Chat", "description": "Synology Chat channel plugin for OpenClaw channels and direct messages.", + "icon": "https://cdn.simpleicons.org/synology/111111", "activation": { "onStartup": false }, diff --git a/extensions/telegram/openclaw.plugin.json b/extensions/telegram/openclaw.plugin.json index da9ac401f1a0..b3ce2c1c53b8 100644 --- a/extensions/telegram/openclaw.plugin.json +++ b/extensions/telegram/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "telegram", + "icon": "https://cdn.simpleicons.org/telegram/111111", "activation": { "onStartup": false }, diff --git a/extensions/twitch/openclaw.plugin.json b/extensions/twitch/openclaw.plugin.json index e5f0e60e3566..dbc2bddb00ab 100644 --- a/extensions/twitch/openclaw.plugin.json +++ b/extensions/twitch/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "twitch", "name": "Twitch", "description": "OpenClaw Twitch channel plugin for chat and moderation workflows.", + "icon": "https://cdn.simpleicons.org/twitch/111111", "activation": { "onStartup": false }, diff --git a/extensions/vercel-ai-gateway/openclaw.plugin.json b/extensions/vercel-ai-gateway/openclaw.plugin.json index e98de6ea975b..9f17044e20b7 100644 --- a/extensions/vercel-ai-gateway/openclaw.plugin.json +++ b/extensions/vercel-ai-gateway/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "vercel-ai-gateway", + "icon": "https://cdn.simpleicons.org/vercel/111111", "activation": { "onStartup": false }, diff --git a/extensions/whatsapp/openclaw.plugin.json b/extensions/whatsapp/openclaw.plugin.json index b12f764447ef..1d15d326eb55 100644 --- a/extensions/whatsapp/openclaw.plugin.json +++ b/extensions/whatsapp/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "whatsapp", "name": "WhatsApp", "description": "OpenClaw WhatsApp channel plugin for WhatsApp Web chats.", + "icon": "https://cdn.simpleicons.org/whatsapp/111111", "skills": ["./skills"], "activation": { "onStartup": false diff --git a/extensions/xiaomi/openclaw.plugin.json b/extensions/xiaomi/openclaw.plugin.json index f2a3785914a5..f27c7101f652 100644 --- a/extensions/xiaomi/openclaw.plugin.json +++ b/extensions/xiaomi/openclaw.plugin.json @@ -1,5 +1,6 @@ { "id": "xiaomi", + "icon": "https://cdn.simpleicons.org/xiaomi/111111", "activation": { "onStartup": false }, diff --git a/extensions/zalo/openclaw.plugin.json b/extensions/zalo/openclaw.plugin.json index 48c1f6dce7e4..cb487f1e2d45 100644 --- a/extensions/zalo/openclaw.plugin.json +++ b/extensions/zalo/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "zalo", "name": "Zalo", "description": "OpenClaw Zalo channel plugin for bot and webhook chats.", + "icon": "https://cdn.simpleicons.org/zalo/111111", "activation": { "onStartup": false }, diff --git a/extensions/zalouser/openclaw.plugin.json b/extensions/zalouser/openclaw.plugin.json index 612d771d82f3..5f223f8726be 100644 --- a/extensions/zalouser/openclaw.plugin.json +++ b/extensions/zalouser/openclaw.plugin.json @@ -2,6 +2,7 @@ "id": "zalouser", "name": "Zalo Personal", "description": "OpenClaw Zalo Personal Account plugin via native zca-js integration.", + "icon": "https://cdn.simpleicons.org/zalo/111111", "activation": { "onStartup": false }, diff --git a/src/plugins/manifest-registry.test.ts b/src/plugins/manifest-registry.test.ts index 226923e3c37f..a224ebc5b18c 100644 --- a/src/plugins/manifest-registry.test.ts +++ b/src/plugins/manifest-registry.test.ts @@ -458,6 +458,26 @@ describe("loadPluginManifestRegistry", () => { expect(manifestChangeCase.secondName).toBe("After"); }); + it("preserves optional manifest icon URLs on registry records", () => { + const dir = makeTempDir(); + writeManifest(dir, { + id: "icon-demo", + name: "Icon Demo", + icon: "https://cdn.simpleicons.org/simpleicons/111111", + configSchema: { type: "object" }, + }); + + const registry = loadRegistry([ + createPluginCandidate({ + idHint: "icon-demo", + rootDir: dir, + origin: "bundled", + }), + ]); + + expect(registry.plugins[0]?.icon).toBe("https://cdn.simpleicons.org/simpleicons/111111"); + }); + it("keeps only the higher-precedence plugin for truly distinct duplicates", () => { const dirA = makeTempDir(); const dirB = makeTempDir(); diff --git a/src/plugins/manifest-registry.ts b/src/plugins/manifest-registry.ts index 4bb054b1a3f7..72cb4e3471a4 100644 --- a/src/plugins/manifest-registry.ts +++ b/src/plugins/manifest-registry.ts @@ -201,6 +201,7 @@ export type PluginManifestRecord = { id: string; name?: string; description?: string; + icon?: string; version?: string; packageName?: string; packageVersion?: string; @@ -487,6 +488,7 @@ function buildRecord(params: { name: normalizeOptionalString(params.manifest.name) ?? params.candidate.packageName, description: normalizeOptionalString(params.manifest.description) ?? params.candidate.packageDescription, + icon: normalizeOptionalString(params.manifest.icon), version: normalizeOptionalString(params.manifest.version) ?? params.candidate.packageVersion, packageName: params.candidate.packageName, packageVersion: params.candidate.packageVersion, diff --git a/src/plugins/manifest.ts b/src/plugins/manifest.ts index 739c3ee6b755..e86707c3a3bf 100644 --- a/src/plugins/manifest.ts +++ b/src/plugins/manifest.ts @@ -376,6 +376,8 @@ export type PluginManifest = { skills?: string[]; name?: string; description?: string; + /** Optional HTTPS URL for marketplace/catalog card artwork. */ + icon?: string; version?: string; uiHints?: Record; /** @@ -1764,6 +1766,7 @@ export function loadPluginManifest( ); const name = normalizeOptionalString(raw.name); const description = normalizeOptionalString(raw.description); + const icon = normalizeOptionalString(raw.icon); const version = normalizeOptionalString(raw.version); const channels = normalizeTrimmedStringList(raw.channels); const providers = normalizeTrimmedStringList(raw.providers); @@ -1856,6 +1859,7 @@ export function loadPluginManifest( skills, name, description, + icon, version, uiHints, contracts,