diff --git a/README.md b/README.md
index dbe5adb..6e956c9 100644
--- a/README.md
+++ b/README.md
@@ -101,6 +101,7 @@ External entries point to upstream packages or repositories. They are counted in
"id": "example-skill",
"name": "Example Skill",
"category": "development",
+ "icon": "",
"tags": ["example"],
"maintainer": {
"name": "Example",
diff --git a/docs/assets/external-skill-icons-v1.2.9.svg b/docs/assets/external-skill-icons-v1.2.9.svg
new file mode 100644
index 0000000..5910870
--- /dev/null
+++ b/docs/assets/external-skill-icons-v1.2.9.svg
@@ -0,0 +1,125 @@
+
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index ad13091..6691634 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,6 +1,6 @@
{
"name": "DesireCore Official Market",
- "version": "1.2.8",
+ "version": "1.2.9",
"schemaVersion": "1.1.0",
"supportedLocales": ["zh-CN", "en-US"],
"defaultLocale": "en-US",
@@ -28,7 +28,7 @@
"stats": {
"totalAgents": 1,
"totalSkills": 50,
- "lastUpdated": "2026-07-11"
+ "lastUpdated": "2026-07-16"
},
"features": [
"curated-index",
diff --git a/scripts/i18n/validate-i18n.py b/scripts/i18n/validate-i18n.py
index 4ea6926..5681cfe 100755
--- a/scripts/i18n/validate-i18n.py
+++ b/scripts/i18n/validate-i18n.py
@@ -17,7 +17,7 @@ Checks:
8. Top-level description is 1-1024 chars (spec); top-level name is 1-64 chars (spec).
9. Skill/Agent counts and builtin skill index match the repository contents.
10. Skill, Agent, and entry.json category references exist in categories.json.
- 11. entry.json pointers have the required marketplace fields and safe source URLs.
+ 11. entry.json pointers have the required marketplace fields, valid inline SVG icons, and safe source URLs.
12. Market Skills set `disable-model-invocation` to true or omit it; false is prohibited.
Exit codes:
@@ -38,6 +38,7 @@ import json
import re
import ssl
import sys
+from xml.etree import ElementTree
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Iterable
@@ -389,7 +390,7 @@ def validate_entry_json(report: Report, entry_file: Path, category_ids: set[str]
if not entry:
return
- required = ("id", "name", "category", "maintainer", "stewardship", "license", "redistribution", "source")
+ required = ("id", "name", "category", "icon", "maintainer", "stewardship", "license", "redistribution", "source")
for key in required:
if key not in entry:
report.add(Issue(rel, "entry-json", f"missing required field '{key}'"))
@@ -401,6 +402,19 @@ def validate_entry_json(report: Report, entry_file: Path, category_ids: set[str]
if not isinstance(category, str) or category not in category_ids:
report.add(Issue(rel, "entry-json", f"category '{category}' is not declared in categories.json"))
+ icon = entry.get("icon")
+ if not isinstance(icon, str) or not icon.strip():
+ report.add(Issue(rel, "entry-json", "icon must be a non-empty inline SVG string"))
+ else:
+ try:
+ root = ElementTree.fromstring(icon)
+ if root.tag != "{http://www.w3.org/2000/svg}svg":
+ report.add(Issue(rel, "entry-json", "icon root element must be svg in the SVG namespace"))
+ elif not root.get("viewBox"):
+ report.add(Issue(rel, "entry-json", "icon SVG must declare a viewBox"))
+ except ElementTree.ParseError as exc:
+ report.add(Issue(rel, "entry-json", f"icon must be valid SVG XML: {exc}"))
+
maintainer = entry.get("maintainer")
if not isinstance(maintainer, dict) or not isinstance(maintainer.get("name"), str):
report.add(Issue(rel, "entry-json", "maintainer.name is required"))
diff --git a/skills/agent-reach/entry.json b/skills/agent-reach/entry.json
index cdb4a05..31bcd29 100644
--- a/skills/agent-reach/entry.json
+++ b/skills/agent-reach/entry.json
@@ -2,6 +2,7 @@
"id": "agent-reach",
"name": "Agent Reach",
"category": "research",
+ "icon": "",
"tags": ["research", "web-search", "social-media", "twitter", "reddit", "youtube", "bilibili", "xiaohongshu"],
"maintainer": {
"name": "Panniantong",
diff --git a/skills/ai-news-radar/entry.json b/skills/ai-news-radar/entry.json
index e61e00f..241df7b 100644
--- a/skills/ai-news-radar/entry.json
+++ b/skills/ai-news-radar/entry.json
@@ -2,6 +2,7 @@
"id": "ai-news-radar",
"name": "AI News Radar",
"category": "productivity",
+ "icon": "",
"tags": [
"ai-news",
"rss",
diff --git a/skills/amap-jsapi-skill/entry.json b/skills/amap-jsapi-skill/entry.json
index e3e6da9..0466675 100644
--- a/skills/amap-jsapi-skill/entry.json
+++ b/skills/amap-jsapi-skill/entry.json
@@ -2,6 +2,7 @@
"id": "amap-jsapi-skill",
"name": "AMap JSAPI Skill",
"category": "development",
+ "icon": "",
"tags": [
"lbs-amap"
],
diff --git a/skills/dingtalk-api/entry.json b/skills/dingtalk-api/entry.json
index 6209384..e6661d8 100644
--- a/skills/dingtalk-api/entry.json
+++ b/skills/dingtalk-api/entry.json
@@ -2,6 +2,7 @@
"id": "dingtalk-api",
"name": "DingTalk API Skill",
"category": "communication",
+ "icon": "",
"tags": [
"ogenes"
],
diff --git a/skills/flyai-skill/entry.json b/skills/flyai-skill/entry.json
index 621a09b..64e6cab 100644
--- a/skills/flyai-skill/entry.json
+++ b/skills/flyai-skill/entry.json
@@ -2,6 +2,7 @@
"id": "flyai-skill",
"name": "FlyAI",
"category": "productivity",
+ "icon": "",
"tags": [
"alibaba-flyai"
],
diff --git a/skills/follow-builders/entry.json b/skills/follow-builders/entry.json
index be76fb8..5937e5a 100644
--- a/skills/follow-builders/entry.json
+++ b/skills/follow-builders/entry.json
@@ -2,6 +2,7 @@
"id": "follow-builders",
"name": "Follow Builders",
"category": "productivity",
+ "icon": "",
"tags": [
"zarazhangrui"
],
diff --git a/skills/ian-xiaohei-illustrations/entry.json b/skills/ian-xiaohei-illustrations/entry.json
index d52a076..a851da6 100644
--- a/skills/ian-xiaohei-illustrations/entry.json
+++ b/skills/ian-xiaohei-illustrations/entry.json
@@ -2,6 +2,7 @@
"id": "ian-xiaohei-illustrations",
"name": "Ian 小黑怪诞正文配图",
"category": "media",
+ "icon": "",
"tags": ["illustration", "image-generation", "xiaohei", "design"],
"maintainer": {
"name": "helloianneo",
diff --git a/skills/karpathy-guidelines/entry.json b/skills/karpathy-guidelines/entry.json
index 457ee16..5c2a9f1 100644
--- a/skills/karpathy-guidelines/entry.json
+++ b/skills/karpathy-guidelines/entry.json
@@ -2,6 +2,7 @@
"id": "karpathy-guidelines",
"name": "Karpathy Guidelines",
"category": "development",
+ "icon": "",
"tags": [
"guidelines",
"best-practices",
diff --git a/skills/khazix-skills/entry.json b/skills/khazix-skills/entry.json
index 1153afd..ecd4a58 100644
--- a/skills/khazix-skills/entry.json
+++ b/skills/khazix-skills/entry.json
@@ -2,6 +2,7 @@
"id": "khazix-skills",
"name": "卡兹克 Skills",
"category": "productivity",
+ "icon": "",
"tags": ["khazix", "ai-news", "writing", "analysis"],
"maintainer": {
"name": "KKKKhazix",
diff --git a/skills/larksuite-cli/entry.json b/skills/larksuite-cli/entry.json
index 5369fbc..62f5213 100644
--- a/skills/larksuite-cli/entry.json
+++ b/skills/larksuite-cli/entry.json
@@ -2,6 +2,7 @@
"id": "larksuite-cli",
"name": "Lark Suite CLI",
"category": "communication",
+ "icon": "",
"tags": [
"larksuite"
],
diff --git a/skills/last30days/entry.json b/skills/last30days/entry.json
index 6b09ad1..ef600ca 100644
--- a/skills/last30days/entry.json
+++ b/skills/last30days/entry.json
@@ -2,6 +2,7 @@
"id": "last30days",
"name": "Last 30 Days",
"category": "research",
+ "icon": "",
"tags": [
"research",
"trends",
diff --git a/skills/luckin-my-coffee/entry.json b/skills/luckin-my-coffee/entry.json
index 5df3450..358557a 100644
--- a/skills/luckin-my-coffee/entry.json
+++ b/skills/luckin-my-coffee/entry.json
@@ -2,6 +2,7 @@
"id": "luckin-my-coffee",
"name": "Luckin My Coffee",
"category": "business",
+ "icon": "",
"tags": [
"luckin"
],
diff --git a/skills/mattpocock-skills/entry.json b/skills/mattpocock-skills/entry.json
index b51e506..6a8057c 100644
--- a/skills/mattpocock-skills/entry.json
+++ b/skills/mattpocock-skills/entry.json
@@ -2,6 +2,7 @@
"id": "mattpocock-skills",
"name": "Matt Pocock Skills",
"category": "development",
+ "icon": "",
"tags": [
"engineering",
"tdd",
diff --git a/skills/minimax-image-gen/entry.json b/skills/minimax-image-gen/entry.json
index 693eddb..8704860 100644
--- a/skills/minimax-image-gen/entry.json
+++ b/skills/minimax-image-gen/entry.json
@@ -2,6 +2,7 @@
"id": "minimax-image-gen",
"name": "MiniMax 图像生成",
"category": "media",
+ "icon": "",
"tags": [
"minimax",
"media"
diff --git a/skills/minimax-tts/entry.json b/skills/minimax-tts/entry.json
index f2a3ce6..ca7fb31 100644
--- a/skills/minimax-tts/entry.json
+++ b/skills/minimax-tts/entry.json
@@ -2,6 +2,7 @@
"id": "minimax-tts",
"name": "MiniMax 语音合成",
"category": "media",
+ "icon": "",
"tags": [
"minimax",
"media"
diff --git a/skills/mt-paotui-for-client/entry.json b/skills/mt-paotui-for-client/entry.json
index 6b09a21..22e4994 100644
--- a/skills/mt-paotui-for-client/entry.json
+++ b/skills/mt-paotui-for-client/entry.json
@@ -2,6 +2,7 @@
"id": "mt-paotui-for-client",
"name": "Meituan Paotui Client",
"category": "business",
+ "icon": "",
"tags": [
"meituan"
],
diff --git a/skills/netease-skills/entry.json b/skills/netease-skills/entry.json
index 9fc3b07..7e61d2a 100644
--- a/skills/netease-skills/entry.json
+++ b/skills/netease-skills/entry.json
@@ -2,6 +2,7 @@
"id": "netease-skills",
"name": "NetEase Skills",
"category": "productivity",
+ "icon": "",
"tags": [
"NetEase"
],
diff --git a/skills/taste-skill/entry.json b/skills/taste-skill/entry.json
index a8c6b8d..6f859da 100644
--- a/skills/taste-skill/entry.json
+++ b/skills/taste-skill/entry.json
@@ -2,6 +2,7 @@
"id": "taste-skill",
"name": "Taste Skill",
"category": "creative",
+ "icon": "",
"tags": [
"taste",
"design",
diff --git a/skills/wechatpay-skills/entry.json b/skills/wechatpay-skills/entry.json
index b16f997..f53c3dc 100644
--- a/skills/wechatpay-skills/entry.json
+++ b/skills/wechatpay-skills/entry.json
@@ -2,6 +2,7 @@
"id": "wechatpay-skills",
"name": "WeChat Pay Skills",
"category": "business",
+ "icon": "",
"tags": [
"wechatpay-apiv3"
],
diff --git a/skills/wecom-cli/entry.json b/skills/wecom-cli/entry.json
index dd8bf1e..f1c8d00 100644
--- a/skills/wecom-cli/entry.json
+++ b/skills/wecom-cli/entry.json
@@ -2,6 +2,7 @@
"id": "wecom-cli",
"name": "WeCom CLI",
"category": "communication",
+ "icon": "",
"tags": [
"WecomTeam"
],