## 为什么 / Why 条目此前是 inline + `listing-only`,详情页显示「仅收录,当前不能由 DesireCore 一键获取」。同期 #115(企微)与 #118(发票助手)都已 `installable`,**飞书是唯一装不了的第三方 Agent**。 inline 形态在这条路上无解:`installable` 要求内容有独立的不可变 ref,而 inline 内容随本仓库走,没有自己的制品 ref。 The listing was inline + `listing-only`, so the client showed it as discovery-only. With WeCom (#115) and Invoice Organizer (#118) already installable, this was the only third-party Agent users could not acquire. Inline form cannot satisfy the installable evidence gate, which requires content pinned to its own immutable ref. ## 顺带修掉一个错误的承诺 / An incorrect claim, fixed along the way 原 `agent.json` 用 `default_enabled.skills` 声明那 23 个 `lark-*` 技能。但该字段的语义是**「本地已有的技能默认启用」**,schema 明确限定 ID 需存在于 Agent 自带 `skills/` 或市场 `builtin-skills` 清单中 —— `lark-*` 两者都不在,**声明落空**。 真正负责「把技能取过来」的是 `required_skills`(desirecore/desirecore#2587)。也就是说,条目 `fullDesc` 里「随 Agent 一并安装 23 个技能,安装后即可使用」在原实现下**做不到**。 上游 `agent.json` 已改用 `required_skills.collections`,两个字段按 schema 的分工同时保留。逐项核对过: | 检查项 | 结果 | |---|---| | 合集 `larksuite-cli` entry 与 children | 存在,28 个 | | 声明的 23 个 ID 是否都在其中 | **全部命中,无缺失** | | source | 公开 git + 固定 ref,可取 | | 合集自身版本门槛 | 无 | | `redistribution` | `allowed` | | 合集是 `listing-only` 是否影响预置 | 否 —— 预置路径不检查 `availability` | ## 形态 / Form 内容移至 [desirecore-agent/feishu-orchestrator](https://github.com/desirecore-agent/feishu-orchestrator),pin 到 `d5b0a78`。market 侧只留 `entry.json` + sidecar + `assets/`。 上游 `agent.json` 已剥净市场卡片字段,并**单独跑过 `agentConfigSchema`** —— pointer 没有 `projectMarketAgentConfigToAgentFs` 那层投影兜底,`persona` 这类卡片字段留着就会让落盘配置非法(本次正是由该校验捕获并修掉的)。 **图片头像保留**:`assets/avatar.webp` 连同 `entry.avatar.image` 一起留在 market 侧,validator 接受 —— pointer 形态不必退回纯文字头像。 ## 证据六项 / Acquisition evidence - `provenance.content`:https + 40 位 SHA - `license`:`known` + `MIT` + `evidencePath: LICENSE` - `compliance`:六字段齐全(含 `noticePath: NOTICE`) - `compliance.reviewedRef === provenance.content.ref` - `timestamps.reviewedAt.value === compliance.reviewedAt` - `availability: installable` 一致性:`entry.maintainer` → sidecar `upstreamMaintainer`;`tags` 用英文 slug 与 `presentation.tags` 逐字一致;`redistribution` 为 `source-pointer-only`;`entry.requiredClientVersion` 与 `compatibility.requiredClientVersion` 一致(`10.0.144`,即包含 #2587 的首个发布版本)。 ## 校验 / Verification | 命令 | 结果 | |---|---| | `validate_catalog_metadata.py --require-complete` | **0 error**,75 sidecars | | `validate-i18n.py` | 0 error | | `test_validate_catalog_metadata.py` | 47/47 | | 上游 `agent.json` 过 `agentConfigSchema` | 通过(捕获并修掉了 `persona` 字段) | Co-authored-by: yi-ge <jackyoncode@gmail.com>
DesireCore Market
DesireCore 官方市场仓库,存放官方维护的 Agent/Team/Skill 定义,以及经过整理的第三方 Skill 入口。
Repository Shape
.
├── manifest.json # Market metadata, supported locales, aggregate stats
├── categories.json # Category registry and localized labels
├── builtin-skills.json # Built-in local SKILL.md skills
├── agents/
│ ├── desirecore/
│ │ └── agent.json
│ └── <agent-listing>/
│ ├── agent.json
│ ├── catalog-metadata.v1.json
│ └── USAGE.md # Optional usage notes (USAGE.<locale>.md for variants)
├── teams/
│ └── <team>/
│ └── entry.json
└── skills/
├── <local-skill>/
│ ├── SKILL.md
│ └── SKILL.<locale>.md
└── <external-entry>/
└── entry.json
The market currently contains:
5Agents:desirecore,dingtalk-workspace,feishu-orchestrator,invoice-organizer,wecom-assistant1Team:contract-review-team40local built-in skills withSKILL.md29external skill entries withentry.json69publishable skills in total (SKILL.md+entry.json)
Skill Sources
Local built-in skills are installable from this repository and must be listed in builtin-skills.json:
baidu-poi-search, ccgp-gov-procurement, clone-agent, cnipa-patent-search, code-intelligence,
configuring-compute, create-agent, creditchina-query, dashscope-image-gen, delete-agent,
dev-environment-setup, discover-agent, docx, frontend-design, guizang-ppt,
image-to-image, mail-operations, manage-skills, manage-teams, markdown,
minimax-music-gen, minimax-video-gen, multi-source-sentiment, nodejs-runtime, pdf, pptx,
presentation-forge, python-runtime, registering-services, s3-storage-operations, skill-creator,
tech-diagram, tianyancha-risk, update-agent, using-services, web-access, workflow, workforce-optimization,
xiaomi-tts, xlsx
builtin-skills.json#retired lists old built-in Skill IDs that clients may safely retire during
startup. Clients only remove copies tracked in skills.lock as market/bundled content whose
SKILL.md hash still matches the installed record; manually installed or locally modified copies
are preserved. An ID must not appear in both skills and retired.
External entries are marketplace pointers to Git/Web/ZIP sources:
agent-reach, ai-news-radar, amap-jsapi-skill, baoyu-skills, dingtalk-api,
dingtalk-cli, flyai-skill, follow-builders, humanizer, humanizer-zh,
ian-xiaohei-illustrations, impeccable, karpathy-guidelines, khazix-skills,
larksuite-cli, last30days, luckin-my-coffee, marketingskills,
mattpocock-skills, minimax-image-gen, minimax-tts, mt-paotui-for-client,
netease-skills, nuwa-skill, taste-skill, watch, watchless,
wechatpay-skills, wecom-cli
Data Formats
Local Skill (skills/<id>/SKILL.md)
Local skills use YAML frontmatter plus Markdown body. The top-level name must equal the directory slug. Display strings live in metadata.i18n.
---
name: web-access
description: >-
Use this skill when ...
version: 2.0.1
type: procedural
risk_level: low
status: enabled
metadata:
author: desirecore
updated_at: '2026-05-05'
i18n:
default_locale: en-US
source_locale: zh-CN
locales: [zh-CN, en-US]
zh-CN:
name: 联网访问
short_desc: 联网搜索、网页抓取、登录态浏览器访问
body: ./SKILL.zh-CN.md
translated_by: human
en-US:
name: Web Access
short_desc: Web search, page fetching, logged-in browser access
body: ./SKILL.md
source_hash: sha256:...
translated_by: human
market:
category: research
channel: latest
maintainer:
name: DesireCore Official
verified: true
---
External Entry (skills/<id>/entry.json)
External entries point to upstream packages or repositories. They are counted in manifest.stats.totalSkills but are not included in builtin-skills.json.
{
"id": "example-skill",
"name": "Example Skill",
"category": "development",
"icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">...</svg>",
"tags": ["example"],
"maintainer": {
"name": "Example",
"verified": false,
"account": "example",
"url": "https://github.com/example/example-skill"
},
"stewardship": "community",
"license": "MIT",
"redistribution": "allowed",
"source": {
"kind": "git",
"repoUrl": "https://github.com/example/example-skill.git",
"repoBranch": "main"
}
}
Team Listing (teams/<id>/entry.json)
A Team is a group of Agents with a supervisor. It is published as a fork pointer
only: the team body (team.json, members.json, shared/) always stays in the
upstream team repository, and the catalog registers just "what it is and where to
fork it from". Installation forks that repository and installs the declared members;
updates are a git pull on the fork. Because both actions are Git actions,
source.kind must be git and source.repoUrl is required — zip and web cannot
express either one — and a Team deliberately has no installPolicy /
updatePolicy pair: it is always market-initiated fork plus repository-driven update.
teams/<id>/ therefore holds exactly entry.json plus the sidecar. There is no
inline form; a team.json in the catalog is rejected.
{
"id": "example-team",
"name": "Example Team",
"category": "development",
"tags": ["example"],
"latestVersion": "0.1.0",
"maintainer": {
"name": "Example",
"verified": false,
"account": "example",
"url": "https://github.com/example"
},
"stewardship": "community",
"license": "MIT",
"redistribution": "source-pointer-only",
"source": {
"kind": "git",
"repoUrl": "https://github.com/example/example-team.git",
"repoBranch": "main",
"ref": "0123456789abcdef0123456789abcdef01234567"
},
"requiredClientVersion": "10.0.0",
"avatar": { "t": "示", "bg": "linear-gradient(135deg, #5856D6, #3634A3)" },
"supervisorName": "Example Supervisor",
"supervisorAgentId": "example-lead",
"memberCount": 3,
"memberNames": ["Example Member One", "Example Member Two"]
}
A Team card is rendered from avatar, not from icon. The client's runtime
projection marketTeamSchema requires avatar and has no icon property at all —
the same is true of marketAgentSchema, while only marketSkillSchema exposes
icon. The entry contract inherits icon from the shared common properties, so it
is accepted, but it can never reach a card. The validator therefore requires icon
on Skill listings only, and warns when an Agent or Team listing declares one.
redistribution stays source-pointer-only for a Team even under a permissive
license: the market never ships the team body, it only points at the repository the
client forks. The license governs what a fork may do; redistribution describes how
the content is delivered, and for teams that is always "fetch from upstream".
supervisorName, supervisorAgentId, memberCount, memberNames and
requiredSkills are display metadata declared by the publisher. They may drift from
the upstream repository, so installation, permissions and member resolution must read
the forked team.json / members.json instead. Teams are counted in
manifest.stats.totalTeams, which the client keeps optional: a catalog with no teams
may omit it, and once the key is present it must be exact.
Catalog metadata sidecar (catalog-metadata.v1.json)
The versioned catalog metadata contract is stored at one fixed path next to each legacy item:
agents/<id>/catalog-metadata.v1.json
teams/<id>/catalog-metadata.v1.json
skills/<id>/catalog-metadata.v1.json
Legacy agent.json, SKILL.md, and entry.json files remain the compatibility
surface for older clients. New clients merge the sidecar through a deterministic
adapter. Any field repeated in both files must have the same value; the validator
rejects drift rather than choosing one copy silently.
Agent listings support exactly one of agents/<slug>/agent.json (inline metadata)
or agents/<slug>/entry.json (an external pointer), alongside the sidecar. Missing
or simultaneous primary files are rejected. For a pointer, entry.id and sidecar
identity.id use the catalog directory slug and identity.kind is agent; the
upstream AgentFS agent.json.id remains its own UUID and must not be rewritten.
An agent listing may also carry an optional USAGE.md next to agent.json. The
client renders it as a separate "Usage" section on the agent detail page, kept
apart from fullDesc (which is persona text and also enters the agent's runtime
context). Localized variants use USAGE.<locale>.md, resolved through the same
fallback chain as the i18n block: requested locale, then i18n.source_locale,
then i18n.default_locale, then the unsuffixed file. Its scope is what a reader
needs before installing — prerequisites, authorization steps, capability and
safety boundaries — not full documentation; clients truncate overlong content.
Longer material belongs in a skill's references/ directory, which the agent
loads on demand. Listings without the file are unaffected and render no section.
Relative image references do not render on the detail page, so keep USAGE.md
text-only. See ADR-143 in the DesireCore repository.
Agent pointers first pass the complete raw client contract in
schemas/market-agent-entry.client.schema.json,
exported from marketAgentEntrySchema in the DesireCore repository at commit
18bbb86f62e1288b1f945209bed74ec72620a9d4. The schema's $comment records the
source blob as well. Refresh this generated snapshot from the TypeScript export
when changing client compatibility; do not replace it with permissive sidecar
validation. Version fields keep their original types and the client's supported
format. Installation/update policies must either both be absent (effective
market/market) or form a complete supported pair; the sidecar must preserve
that effective pair.
Agent pointer latestVersion maps to sidecar release.version; optional
requiredClientVersion, installPolicy, and updatePolicy must agree with the
sidecar compatibility/spec fields. Pointer source fields must describe the same
artifact as provenance.content, and maintainer maps to upstreamMaintainer.
An installable Agent pointer must itself pin source.ref (Git) or source.sha256
(Web/ZIP); an immutable ref supplied only by the sidecar cannot pin a mutable
entry. Existing immutable-source, license, governance-review and complete-coverage
checks still apply. Agent pointers do not receive the built-in Skill exceptions.
Agent 目录必须在 agent.json 内联元数据和 entry.json 外部指针中二选一,并提供 sidecar。
Pointer 原始 JSON 先通过固定客户端提交导出的完整 Schema;版本类型与格式、来源路径和策略组合不能由 sidecar 掩盖。
Pointer 的目录 slug、entry.id、sidecar identity.id 必须一致;上游 AgentFS 的 UUID 不改写。
安装/更新策略双缺省时有效值仍是 market/market,sidecar 不得将其改成系统条目。
latestVersion、最低客户端版本和安装/更新策略须与 sidecar 对齐;来源必须是同一个制品。
可安装指针自身必须固定 Git ref 或 Web/ZIP 摘要,不能只在 sidecar 宣称不可变版本。
现有许可、治理审查、不可变来源和完整覆盖门禁继续有效,不适用内置 Skill 的宽松例外。
Team listings are pointer-only, so teams/<slug>/ carries exactly entry.json plus
the sidecar; an inline team.json is rejected. Team pointers first pass the complete
raw client contract in
schemas/market-team-entry.client.schema.json,
exported from marketTeamEntrySchema the same way as the Agent snapshot; its
$comment records the source commit and blob. entry.id, the directory slug and
sidecar identity.id must agree, identity.kind is team, and latestVersion maps
to release.version. supervisorName, supervisorAgentId, memberCount,
memberNames, requiredSkills and requiredClientVersion are compared symmetrically:
the sidecar may neither drop a fact the pointer declares nor invent one it omits,
because the client reads the pointer and a version gate that exists only in the
sidecar would not gate anything. Pointer source fields must describe the same
artifact as provenance.content, and an installable Team pointer must itself pin a
full-SHA source.ref — a tag is not a reproducible pin, because a tag can be moved
to a different commit after the listing is reviewed.
团队条目只有指针形态:teams/<slug>/ 仅放 entry.json 与 sidecar,目录内出现 team.json 直接判非法。
Pointer 原始 JSON 先通过由 marketTeamEntrySchema 导出的完整客户端 Schema;
source.kind 恒为 git 且必须有 repoUrl,团队没有 installPolicy / updatePolicy 组合。
目录 slug、entry.id、sidecar identity.id 必须一致,identity.kind 为 team。
展示字段与最低客户端版本双向比对:sidecar 既不得丢弃指针声明的事实,也不得凭空补上指针没有的事实。
可安装团队指针自身必须固定完整 SHA 的 source.ref,tag 或分支不算可复现锁定。
The sidecar records source-owned presentation, release, timestamp, content
provenance, governance, compatibility, and type-specific facts. It deliberately
cannot declare catalogSourceId, catalog commit/path/trust, effective official
status, installation state, device state, health, URLs discovered at runtime, or
syncedAt. DesireCore injects trusted catalog provenance and runtime facts.
license.evidencePath, compliance.licenseEvidencePath and compliance.noticePath
resolve differently by item shape, because the schema constrains only the string
form. Vendored content (built-in Skills, inline Agents) ships inside this repository,
so the path is relative to the catalog item directory and the file must actually be
there — a missing file is an error. A pointer distributes nothing, so its evidence
can only be inside the upstream snapshot at the pinned revision; the validator cannot
read that offline, so it warns when such a claim is made against an unpinned pointer.
Pin source.ref to a full commit SHA and the claim becomes falsifiable by anyone who
fetches it.
Time facts are explicit known/unknown values. A known day uses
YYYY-MM-DD with precision: "day"; a known second uses an RFC 3339 UTC value
ending in Z with precision: "second". Never use the current date, clone time,
or synchronization time to fill an unknown catalog or release timestamp.
Collection children stay in their parent's sidecar. Each child declares the
canonical skill + parentId + id identity and its own release fact; a collection
parent may have an unknown version, and a child version must not be inferred from
the parent.
The strict source schema is
schemas/catalog-metadata.v1.schema.json.
Categories
Valid category slugs are declared in categories.json:
productivity, development, business, creative, design, media,
communication, research, data, management
Validation
Run these checks before submitting changes:
# Full market + i18n validation
uv run scripts/i18n/validate-i18n.py
# Catalog sidecar validator unit tests and standalone validation
uv run scripts/catalog/test_validate_catalog_metadata.py
uv run scripts/catalog/test_collection_generator.py
uv run scripts/catalog/validate_catalog_metadata.py
# Translation freshness check
uv run scripts/i18n/translate.py --check
# Verify pinned collection children without changing entry.json (network required;
# mutable collections are reported and skipped because their output is not reproducible)
uv run scripts/gen-collection-children.py --check
# Optional network check for entry.json source URLs
uv run scripts/i18n/validate-i18n.py --online
The validators check market stats, category references, builtin-skills.json,
entry.json structure, sidecar schema and legacy consistency, immutable source
evidence, collection identity, i18n completeness, and translation freshness.
Human-locked translations (translated_by: human) must keep source_hash
aligned after manual review. During a data migration,
scripts/catalog/validate_catalog_metadata.py --require-complete additionally
requires one sidecar for every top-level Agent, Team and Skill.
Detailed i18n guidance is in docs/I18N.md.
License
MIT License. See LICENSE.