## 背景 / Background
主仓 [#2600](https://github.com/desirecore/desirecore/pull/2600)
给市场详情页加了「使用说明」区块,按约定文件名 `USAGE.md` 消费。飞书编排助手此前没有这个文件,详情页不渲染该区块——README
里的前置条件、授权步骤与边界,只有访问 GitHub 才看得到,而真正需要它的是市场里正准备安装的人。
The market detail page gained a Usage section in desirecore#2600,
sourced from a conventional `USAGE.md`. This agent had none, so the
section stayed hidden — its prerequisites, auth steps and limits were
reachable only by visiting GitHub.
## 改动 / Changes
- 上游新增
`USAGE.md`([desirecore-agent/feishu-orchestrator@6116ad4](6116ad4ac7))
- 本条目重新 pin 到该 commit,证据六项同步更新
## 为什么放上游而不是条目目录 / Why upstream
`sync/market.ts` 有两条读取路径,只有一条读本地条目目录:
| 方法 | 本地条目目录基线 | 远程 |
|---|---|---|
| `readAgentDetail`(inline 形态) | ✅ `readUsageDocFromDir` | 有则覆盖 |
| `readAgentDetailFromPointer`(**本条目**) | ❌ 无 | 仅远程 |
所以 pointer 条目的使用说明只能来自上游仓库。条目目录放 `USAGE.md` 对本条目无效。
## 为什么只有无后缀版本 / Why no locale variants
远程抓取时,`USAGE.<locale>.md` 的探测列表由 `extractDeclaredLocales` 从**上游
agent.json 的 `i18n.locales`** 得出;无后缀 `USAGE.md` 则总是被抓。
而 `agentConfigSchema` 顶层没有 `i18n`,根级 `additionalProperties: false`——给上游
agent.json 加这个字段会让 pointer 形态的安装校验直接失败。因此本条目只提供无后缀 `USAGE.md`。
## 内容 / Content
按 `usage-doc.ts` 的定位写「装之前该知道什么」,不是全量文档(3212 字符,上限
16000):第三方分发免责、四步授权、审批模式取舍、安全边界、已验证/未验证清单。各业务域的实测细节仍在上游 `docs/` 的 13 篇里。
两处与既有同类文档(`dingtalk-workspace/USAGE.md`)不同,是核对 `app/data/i18n/zh-CN.ts`
后的修正而非照搬:
- 审批模式是 **7 种**不是 6 种,补上 `allow-all`(全部放行)
- `ask-external` 的语义是「内置工具与命令放行,仅
MCP、HTTP、脚本等外部工具需审批」,**不是**「交给外部系统裁决」——两者含义相反,照搬会让用户以为自己收紧了,实际放宽了命令执行
## 验证 / Verification
证据六项一致性自检全部通过:
```
content.ref == entry.source.ref ✅ 6116ad4ac
reviewedRef == content.ref ✅
timestamps.reviewedAt == compliance.reviewedAt ✅ 2026-09-06
availability ✅ installable
license ✅ known + LICENSE
requiredClientVersion ✅ 10.0.144
```
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.