skillhub/openspec/changes/add-skill-suites/design.md
XiaoSeS accd0e1f67 docs(spec): define skill suite lifecycle and compatibility
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-07 16:52:26 +08:00

22 KiB
Raw Blame History

Context

SkillHub 的现有发布单元是一个根目录包含 SKILL.md 的 Skill 包。SkillVersion 独立完成包校验、安全扫描、可见性审核、发布和下架。Agent Skills 开放规范同样只认识一个目录中的一个 SKILL.md,没有 Suite 协议。

外部方案提供了三类参考Vercel 把多 Skill 仓库作为安装来源Claude Plugin/Superpowers 把多个能力封装为特定 Agent 的版本化插件;腾讯 SkillSet 和 VS Code Extension Pack 把集合建成独立资源。SkillHub 选择轻量集合模型Suite 管理精确的已发布 SkillVersion 引用,成员仍是独立 Skill。

Ubiquitous language

Term Definition
Skill 可独立发布、扫描、审核、搜索和安装的 Agent Skill。
Suite Namespace 所有的、可版本化的 Skill 集合;它不是 Skill也不是多 Skill ZIP。
SuiteVersion Suite 在某一时刻不可变的成员快照和元数据。
Member SuiteVersion 引用的一个精确、已发布 SkillVersion。
Entry Skill 可选的普通 Member用于表达工作流入口不通过名称推断。
Install plan 服务端解析出的 SuiteVersion、成员精确版本、fingerprint 和下载信息。
Degraded Suite 已发布 SuiteVersion 的至少一个成员当前不可下载;历史快照仍可查看,但不能完整安装。

Goals / Non-Goals

Goals:

  • 一次选择和安装一组经过策划的 Skill并保证失败时不留下半套结果。
  • 保留每个 Skill 的独立身份、版本、所有权、扫描、审核、搜索和安装能力。
  • 让 SuiteVersion 成为可重现的精确成员快照,而不是随成员 latest 漂移的查询。
  • 兼容现有 Skill 协议和不同 Agent 的标准 Skill 目录。
  • 复用 Namespace 权限、可见性和审核原则,并明确 Suite 与成员生命周期的边界。

Non-Goals:

  • 不把 SUITE.yaml 放进多 Skill ZIP 并由服务端自动创建成员 Skill。
  • 不让 Suite 发布、审核、下架、隐藏或删除操作级联改变成员 Skill。
  • 不实现嵌套 Suite、版本范围、动态 latest、条件成员、成员别名或跨 Registry 引用。
  • 不把 MCP、Agent、Hook、LSP 或运行时配置纳入 Suite。
  • 不在 v1 提供 Suite promotion、评分、评论或成员自动升级策略。

Decisions

1. Suite 是独立聚合,不是新的 Skill 包格式

新增三个核心关系:

SkillSuite 1 ── * SkillSuiteVersion 1 ── * SkillSuiteVersionMember * ── 0..1 SkillVersion

建议持久化字段:

skill_suite
  id, namespace_id, slug, display_name, summary,
  status, latest_version_id, hidden, hidden_at, hidden_by,
  created_by, created_at, updated_by, updated_at

skill_suite_version
  id, suite_id, version, status, visibility, changelog, entry_skill_version_id,
  published_at, yanked_at, yanked_by, yank_reason,
  created_by, created_at

skill_suite_version_member
  suite_version_id, skill_version_id(nullable), position,
  namespace_slug_snapshot, skill_slug_snapshot,
  skill_version_snapshot, fingerprint_snapshot

成员表保存外键和不可变快照。SkillVersion 被治理性硬删除时,外键使用 ON DELETE SET NULLSuite 历史仍显示原坐标、版本和 fingerprint并被标记为不可用。Suite 不阻塞必要的数据删除,也不伪装成仍可安装。

可见性属于 SuiteVersion 的审核快照,而不是覆盖全部历史版本的 Suite 容器字段。列表和默认详情展示 latestVersionId 对应的可见性;读取或安装历史版本时使用该版本自己的可见性并叠加实时 Member 权限检查。

Alternative: 一份 Suite ZIP 创建 N 个 Skill。拒绝因为会引入部分发布、重复扫描、N 个审核任务、所有权覆盖和回滚困难。

2. Skill 与 Suite 使用类型化身份

完整身份为:

(resourceType, namespaceSlug, slug)

因此 SKILL @global/marketingSUITE @global/marketing 可以同时存在。数据库分别约束 skill(namespace_id, slug)skill_suite(namespace_id, slug),不建立跨类型唯一约束。

命令、API、Web URL 和搜索结果必须携带类型:

skillhub install @global/marketing
skillhub suite install @global/marketing

/api/v1/skills/...
/api/v1/suites/...

现有无类型 skillhub install 永远按 Skill 解析,不能根据搜索结果自动猜测 Suite。

Alternative: 在同一 Namespace 中跨类型保留 slug。拒绝因为限制了正常命名且类型化入口已经能够消除机器歧义。

3. SuiteVersion 引用精确的已发布 SkillVersion

作者可以在 suite.yaml 中选择成员坐标和版本:

apiVersion: skillhub.iflytek.com/v1alpha1
kind: SkillSuite
metadata:
  namespace: global
  slug: superpowers
  version: 1.0.0
  displayName: Superpowers
spec:
  visibility: PUBLIC
  entrySkill: "@global/using-superpowers@1.0.0"
  members:
    - skill: "@global/using-superpowers"
      version: 1.0.0
    - skill: "@global/brainstorming"
      version: 2.1.0

该文件是 API/CLI 的创作输入,不是下载到 Agent 的包。服务端在创建 SuiteVersion 时解析并保存精确 skillVersionId 和 fingerprint。一个 SuiteVersion 最多包含 100 个不同 Skill同一 Skill 不允许重复出现。

成员发布新版本不会改变已有 SuiteVersion。采用新版本、添加、删除、重排成员或修改 Entry Skill 都必须创建新的 SuiteVersion。

为了降低创作成本Web/CLI 在添加 Member 时默认推荐该 Skill 当前可安装的最新版本,但保存时立即解析为精确 skillVersionId、version 和 fingerprint并向作者展示实际固定的版本。作者可以显式选择其他仍处于 PUBLISHED 的历史版本。

不得在已发布 SuiteVersion 中保存 latest 或在安装时重新解析最新版本。可以提供“更新成员版本”辅助操作,但该操作必须先展示版本差异,并创建或修改 DRAFT SuiteVersion它不是后台自动升级。

Member 从当前 SkillHub Registry 的专用候选查询中选择,而不是让前端加载全部 Skill 后自行过滤,也不直接复用只覆盖公开市场的普通搜索。候选查询接收 Suite Namespace、目标可见性和搜索条件服务端只返回当前用户可读取的 ACTIVE、非 hidden、具有 PUBLISHED 可安装版本的 Skill并给出版本列表和与目标 Suite 的兼容性结果。默认推荐最新可安装版本但最终保存精确版本。v1 不支持外部 Registry 成员。

成员版本失效时按阶段处理:

发生阶段 处理方式
创建或编辑 DRAFT 前 无法选择不可安装版本;已经选中的版本标记错误
提交审核时 重新校验并阻止提交,保留 DRAFT
等待审核期间 审核通过前重新校验;失败时保持 PENDING_REVIEW 并给出阻塞成员
SuiteVersion 发布后 不改写快照和 PUBLISHED 状态,计算为 degraded 并阻止整组安装
可逆条件恢复后 hidden、archive 或访问范围恢复且成员精确版本仍可安装时,自动重新计算为 available
YANKED 或硬删除 不自动换到新版本;创建新的 SuiteVersion 并显式选择有效成员版本

Alternative: 保存版本范围或 latest。推迟,因为相同 SuiteVersion 会随时间解析出不同内容,破坏可重复安装和审计。

4. Suite 与 Skill 生命周期相互独立

Skill 继续使用现有生命周期:

上传 → SCANNING/SCAN_FAILED → UPLOADED → PENDING_REVIEW
     → PUBLISHED → YANKED

Suite 没有可执行包不进入扫描状态。SuiteVersion 使用:

DRAFT → PENDING_REVIEW → PUBLISHED → YANKED
                     ↘ REJECTED

PRIVATE Suite 按现有 PRIVATE Skill 原则允许授权管理者从 DRAFT 直接发布。PUBLIC 和 NAMESPACE_ONLY Suite 进入一次 Suite 级审核。审核只检查 Suite 元数据、成员组成、可见性和可安装性,不重新审核成员 Skill。

Suite 容器复用 ACTIVE/ARCHIVED 和独立的 hidden 治理覆盖。Suite 的发布、拒绝、下架、隐藏、归档或删除都不改变任何 Member。Skill 的新版本、下架、隐藏、归档、可见性变化或硬删除也不改写已经发布的 SuiteVersion。

在 Suite 提交审核、审核通过和安装三个时间点都重新验证成员资格,防止期间状态或权限发生变化。

提交与发布流程

阶段 Skill Suite 二者关系
创建内容 上传一个包含 SKILL.md 的包并创建 SkillVersion 创建 SuiteVersion选择已经发布的精确 SkillVersion Suite 不接收或拆分 Skill 包
校验 校验包结构、文件类型和元数据 校验成员存在、已发布、无重复、可见性兼容及 Entry Skill 合法 Suite 复用成员已有结果,不重新校验成员包
安全扫描 进入 SCANNING,成功后进入 UPLOADED,失败进入 SCAN_FAILED 无扫描状态 Suite 没有可执行包,因此不创建扫描任务
提交审核 PUBLIC/NAMESPACE_ONLY SkillVersion 进入 PENDING_REVIEW PUBLIC/NAMESPACE_ONLY SuiteVersion 进入 PENDING_REVIEW Suite 只产生一个自己的审核任务,不复制成员审核任务
审核通过 SkillVersion 进入 PUBLISHED 再次检查全部成员后SuiteVersion 进入 PUBLISHED Suite 发布不修改成员;成员必须仍可用于该 Suite
安装 安装一个 SkillVersion 先解析并校验整组成员,再以客户端事务安装全部成员 Agent 最终只看到标准 Skill 目录
后续变更 新版本、下架、隐藏、归档或删除只作用于该 Skill 新版本、下架、隐藏、归档或删除只作用于该 Suite 已发布 SuiteVersion 不被自动改写;成员失效时 Suite 显示 degraded

这意味着 Suite 是成员 Skill 的“版本化清单”,不是它们的父生命周期。删除 Suite 不删除 Skill更新 Skill 不更新 Suite更新 Suite 也不重新发布 Skill。

5. 审核任务支持类型化目标

现有 review_task 只指向 SkillVersion。为了保留一个审核中心和一致权限规则将其扩展为类型化审核目标

subject_type: SKILL_VERSION | SUITE_VERSION
subject_version_id

现有 Skill 审核行回填为 SKILL_VERSION,旧 Skill 字段在兼容迁移完成前保留。领域服务通过目标处理器完成状态转换,避免 Suite 复制一整套审核控制器和权限判断。

Suite 属于 Namespace不形成脱离 Namespace 的永久个人所有权。Namespace MEMBER 可以创建 Suite并在仍属于该 Namespace 时管理自己创建的 DRAFT/REJECTED Suite 和提交新版本OWNER/ADMIN 可以管理该 Namespace 下全部 Suite。创建者离开 Namespace 后立即失去这类管理权Suite 及其审核历史仍属于 Namespace由 OWNER/ADMIN 接管。GLOBAL Namespace 沿用现有平台投稿和审核规则。

审核权限沿用当前 Namespace/平台角色原则提交者可以查看自己的审核TEAM OWNER/ADMIN 按现有规则审核GLOBAL 使用平台审核角色;自审限制不因 Suite 改变。

Alternative: 新建 suite_review_task。拒绝,因为会产生第二个审核中心、重复权限规则,并增加未来治理能力的分叉。

6. Suite 可见范围不能宽于任一成员

发布时必须满足Suite 的全部潜在安装者都有权读取每个 Member。具体规则为

  • PUBLIC Suite 的所有成员必须为 PUBLIC。
  • NAMESPACE_ONLY Suite 的成员必须为 PUBLIC或属于 Suite 同一 Namespace 且为 NAMESPACE_ONLY不能包含 PRIVATE Member。
  • PRIVATE Suite 的成员可以为 PUBLIC或属于 Suite 同一 Namespace 的 NAMESPACE_ONLY/PRIVATE不能引用其他 Namespace 的非 PUBLIC Member。

这些规则检查的是 Suite 的目标受众,而不只是当前操作者。创建者必须具备 Suite 所属 Namespace 的当前投稿权限,并在引用时能够读取每个精确 Member。

安装时仍逐个执行实时授权和可下载性检查。成员后续变为不可见、YANKED、hidden、ARCHIVED 或被硬删除时SuiteVersion 进入可观察的 degraded 状态;安装整体失败,并指出阻塞成员,不自动替换为其他版本。

权限和可见性变化遵循以下原则:

  • Member 从 PUBLIC 收窄为 NAMESPACE_ONLY/PRIVATE导致已发布 Suite 的目标受众不再全部可访问时Suite 变为 degraded。
  • Member 扩大可见范围且重新满足规则时Suite 可用性自动恢复,不创建新 SuiteVersion。
  • 用户离开 Namespace 后,立即失去 NAMESPACE_ONLY Suite 及其同 Namespace Member 的访问权Suite 不缓存历史授权。
  • Suite 创建者离开 Namespace 后,其 createdBy 仅保留为审计事实,不再授予管理权或 PRIVATE Suite 访问权;已发布 Suite 继续存在OWNER/ADMIN 可以接管。
  • Suite 的可见性变化属于新的发布决策,必须通过新 SuiteVersion 和对应审核完成;临时隐藏/恢复仍使用治理覆盖。
  • 安装计划在返回任何下载地址前校验 Suite 和全部 Member。无权查看 Member 的用户只获得不泄露私有元数据的通用失败信息;管理员可查看具体阻塞成员。

Suite 操作权限为:

操作 权限
创建 Suite 当前 Namespace MEMBER/ADMIN/OWNERGLOBAL 沿用现有平台投稿规则
编辑自己的 DRAFT/REJECTED、提交新版本 创建者仍是当前 Namespace 成员,或 Namespace ADMIN/OWNER
管理任意 Suite、接管离职用户内容 Namespace ADMIN/OWNER平台治理角色按现有规则处理
查看 PUBLISHED Suite PUBLIC 为所有人NAMESPACE_ONLY 为当前 Namespace 成员PRIVATE 为当前创建者及 Namespace ADMIN/OWNERSUPER_ADMIN 可治理查看
查看 DRAFT/REJECTED 当前创建者、Namespace ADMIN/OWNER 和有治理权限的平台角色
查看 PENDING_REVIEW 提交者、Namespace ADMIN/OWNER 和有权审核的角色
安装 Suite 先满足 SuiteVersion 自身可见性,再满足全部 Member 的实时访问和可安装条件

这里的“当前创建者”必须仍属于 Suite Namespace。离开 Namespace 后不再通过历史 createdBy 获得访问权。

7. Suite 不在 Agent 目录中伪装成 Skill

安装 Suite 时,成员按普通 Skill 安装到各 Agent 的标准 Skill 根目录。Suite 不创建:

<skills-root>/<suite-slug>/SKILL.md

如果 Suite 表达工作流,entrySkillVersionId 指向一个普通 Member。Entry Skill 可以与 Suite 同名,也可以不同名;关系只来自显式 ID不由 slug 推断。

这避免腾讯 SkillSet 当前把编排提示写入普通 Skill 目录造成的覆盖问题,也保证所有 Agent 只需理解标准 Skill。

8. Suite 安装是一个客户端事务

skillhub suite install 执行:

  1. 解析一个精确 SuiteVersion 和全部 Member。
  2. 检查 Suite/成员权限、状态、目标目录、现有来源冲突和空间限制。
  3. 下载全部成员到目标根目录内的临时目录。
  4. 校验每个成员的 fingerprint 和 Skill 元数据。
  5. 按稳定顺序获取所有目标锁,备份将被替换的同源目录。
  6. 移动全部成员并一次性写入 inventory。
  7. 任一步失败时恢复所有备份并保持原 inventory。

服务端只返回安装计划和成员下载能力不尝试对用户文件系统提供分布式事务。CLI 在现有 staged install、target lock 和 rollback 机制上扩展为多成员计划。

9. inventory 记录来源集合而不是单一所有者

inventory schema 增加 suites,并让 Skill 安装目标记录来源集合:

{
  "items": [
    {
      "registry": "https://registry.example.com",
      "namespace": "global",
      "slug": "brainstorming",
      "version": "2.1.0",
      "fingerprint": "sha256:...",
      "installedBy": ["direct", "suite:@global/superpowers@1.0.0"],
      "targets": []
    }
  ],
  "suites": [
    {
      "registry": "https://registry.example.com",
      "namespace": "global",
      "slug": "superpowers",
      "version": "1.0.0",
      "members": ["@global/brainstorming@2.1.0"]
    }
  ]
}

卸载 Suite 只移除对应来源引用。仍被直接安装或被其他 Suite 引用的 Skill 保留;仅由该 Suite 引入且未被本地修改的成员才自动删除。检测到本地修改时保留目录并报告,不做破坏性清理。

10. 查询、升级和展示保持类型明确

新增的类型化资源发现入口返回 resourceTypeWeb 使用类型徽标及独立 /skills/.../suites/... 页面。现有 Skill 搜索接口继续只返回 Skill避免旧 CLI 或第三方客户端把 Suite 响应按 Skill 反序列化。Suite 详情显示版本、精确成员、Entry Skill、可用状态和阻塞原因。

suite check 比较 inventory 快照、磁盘 fingerprint 和远端 SuiteVersionsuite upgrade 先显示成员增删改计划,再使用与安装相同的原子流程应用新的精确 SuiteVersion。升级不会单独追随 Member 的最新版本。

11. 生命周期兼容通过隔离状态与能力协商保证

SkillVersion 和 SuiteVersion 使用独立状态类型。不得把 Suite 专属状态加入现有 SkillVersionStatus,也不得因为成员失效或恢复而改写现有 SkillVersion 状态。Suite 的 degraded 是根据成员当前可用性计算出的展示/安装状态,不是 SkillSuiteVersionStatus 的持久化生命周期值。

Server 和 CLI 按以下组合兼容:

组合 预期行为
旧 CLI + 新 Server 原有 Skill 搜索、解析、下载和安装完全不变;旧 CLI 看不到 Suite也不会误装 Suite
新 CLI + 旧 Server 普通 Skill 命令正常Suite 命令通过能力探测得到“不支持 Suite”的明确结果不猜测接口或回退成 Skill 安装
新 CLI + 新 Server 使用 Suite 专用命令、类型化接口和新版 inventory
已安装旧 inventory + 新 CLI 缺少 Suite 字段时按空集合读取;首次 Suite 写入时原子升级 schema不改变已有 Skill 记录
新 Server + 旧数据库数据 数据库迁移只新增表和兼容字段;已有 Skill、ReviewTask 和审计记录含义不变

能力探测应使用 Server 已有版本/能力入口,或新增稳定的 capability 字段;不得仅依赖 HTTP 404 推断,因为 404 也可能代表代理路径或权限配置错误。Suite API、Suite 状态和 Suite review subject 必须以增量方式加入 OpenAPI现有 Skill 字段不得改名或改变枚举含义。

审核迁移采用双读/兼容窗口:现有 Skill 审核数据仍能通过旧的 Skill 关联字段读取,新写入的 Suite 审核使用类型化 subject确认所有运行版本均支持新结构后才允许在后续迁移中收紧旧字段。应用回滚期间保留新增表和字段禁止回滚数据库结构。

12. 拒绝重提和安装统计采用可追溯语义

SuiteVersion 被拒绝后允许由管理者退回 DRAFT保留原审核记录并修改未发布版本后再次提交。PUBLISHED/YANKED SuiteVersion 永远不可编辑;这些版本的任何变化都创建新 SuiteVersion。每次重新提交创建新的审核轮次不覆盖旧决定。

一次 Suite 安装计划使用服务端生成的唯一 operationId 串联一条 Suite 安装计划审计和多条 Member 下载审计。服务端成功签发完整安装计划后Suite 安装请求数增加一次;计划内每个 Member SkillVersion 按现有下载统计口径增加一次,并标记 source=SUITE。同一 operationId 的安全重试不得重复计数。

服务端无法可靠知道 CLI 最终是否完成本地文件提交,因此该指标表示“安装计划/下载已签发”不宣称是本地安装成功数。CLI 后续校验或提交失败不反向扣减服务端计数v1 不增加客户端完成回调或遥测上报。

Risks / Trade-offs

  • 审核表从 Skill 专用扩展为类型化目标 → 使用增量迁移、回填和兼容读取,保留现有 Skill 审核回归测试。
  • 成员状态改变会使历史 Suite 无法安装 → 保留不可变快照、展示 degraded 原因,禁止静默换版。
  • 多成员、多 Agent 目标导致锁和回滚复杂 → 限制 100 个成员预检后按规范化路径排序加锁inventory 最后原子写入。
  • 共享成员卸载可能误删直接安装内容 → inventory 保存多来源引用,本地修改和来源不明时 fail closed。
  • Skill/Suite 同 slug 可能让自然语言含糊 → CLI、API、URL、搜索结果和安装提示始终携带资源类型install 固定解析 Skill。
  • 在现有 Skill 搜索中直接混入 Suite 会破坏旧客户端 → 保留 Skill-only 旧接口,另增类型化资源发现入口。
  • 审核目标和状态枚举扩展可能破坏滚动升级 → Suite 使用独立状态;审核表按兼容窗口增量迁移,并在混合版本验证后再收紧旧字段。
  • 不支持一份 ZIP 创建全部成员,首次迁移多 Skill 仓库仍需发布成员 → v1 优先保证领域和生命周期正确;以后可增加调用现有发布 API 的批量 CLI 编排,但不改变 Suite 模型。

Migration Plan

  1. 新增 Suite 三张表、索引和类型化审核字段;回填现有审核任务为 SKILL_VERSION
  2. 先发布兼容旧 API 的 Server新表为空时现有行为不变。
  3. 发布 Web 的 Suite 管理和类型化审核展示,重新生成 OpenAPI 类型。
  4. 发布支持 Suite 和新版 inventory 的 CLI读取旧 inventory 时将缺少的 suitesinstalledBy 视为空。
  5. 用本地 exact-SHA 镜像验证 Skill 正常流、Suite 生命周期、成员失效和整组回滚。

回滚应用版本时保留新增表和字段,旧版本忽略它们;在确认没有 Suite 数据前不得删除迁移结构。

Open Questions

以下内容明确推迟,不阻塞 v1

  • 是否提供“批量发布成员后创建 Suite”的 CLI 编排。
  • 是否为 Suite 增加收藏、评分、评论和独立订阅。
  • 是否允许跨 Registry Suite 或对外导出通用集合清单。
  • 是否在后续支持 Suite promotion 和组织级强制安装策略。