# ADR-0017 第三方技能:skills.sh 目录 + GitHub 固定提交,两个引擎共用 - 状态:Accepted · 日期:2026-10-23 · 补充 ADR-0016 ## 背景 官方技能仓库只覆盖少量场景。[skills.sh](https://skills.sh) 是社区技能目录,收录 GitHub 仓库中的 SKILL.md 技能,提供搜索接口(`GET https://skills.sh/api/search?q=…`,返回 `source`=owner/repo、`skillId`、`installs`)。第三方技能是通用格式,两个引擎都能用。 ## 决策 - **一个目录,两个引擎**:第三方技能安装在 `/managed-skills/community`(服务可写的数据目录;在沙箱中单独开放只读),采用 Claude 插件格式(`.claude-plugin/plugin.json`,name = `community-skills`;技能在 `skills//`)。 - Claude:运行时按路径作为本地插件加载 - Codex:通过 `skills/extraRoots/set` 加入。已验证(codex 0.164):Codex 会读取上级目录的 plugin.json,技能名显示为 `community-skills:` - 两个引擎的技能 ID 一致:`community-skills:` - **流程:搜索 → 预览 → 安装** - 搜索走 skills.sh - 预览时服务端取仓库默认分支的最新提交(GitHub API `commits/HEAD`),下载该提交的压缩包(≤ 50 MB,缓存在 `data/skill-catalogs/github/__/`,每个仓库只保留最新快照),定位技能目录,返回 SKILL.md 全文、文件列表、许可证与是否含脚本 - 后台必须勾选"已阅读"才能安装 - 安装使用**预览时的提交号**,不会装上未看过的内容;更新也是重新预览后再安装 - **定位技能**:在仓库中(深度 ≤ 6)查找 SKILL.md。优先 frontmatter `name` 等于 skillId 的目录,其次目录名相同的目录,多个匹配时取路径最短的。安装目录名取 SKILL.md 的 `name`,这样 Claude 与 Codex 的技能名一致。 - **许可**:只允许开源许可,其余拒绝安装。 - 识别顺序:技能目录中的 LICENSE 文件 → SKILL.md 的 `license` 字段(SPDX)→ 仓库根目录的 LICENSE - 接受的许可:MIT、Apache、BSD、ISC、MPL、Unlicense、CC0 等 - 拒绝:专有许可、"governed by …"类第三方条款,以及无法识别的许可 - **官方仓库不走这里**:`anthropics/skills`、`openai/skills` 在搜索结果中标记为不可安装,提示到各自引擎的页面安装(官方技能不交叉使用,ADR-0016)。 - **默认不启用**:Profile 选择"全部技能"时**不包含**第三方技能,必须取消"全部"后单独勾选。 - Claude:`resolveSkills` 跳过 `optIn` 插件 - Codex:`skillsToDisable` 在 `all` 时禁用 `community-skills:*` - **文件安全**: - 安装只复制普通文件,跳过符号链接,防止仓库中的链接指向服务器上的文件 - 单个技能最多 500 个文件、20 MB - owner/repo 严格校验,不能以 `.` 开头 - 技能目录在两个引擎的沙箱中只读可见,脚本与其他命令一样受沙箱限制 ## 后果 - 第三方技能未经审核,风险由管理员在预览时判断;审计日志记录来源、提交号、路径和许可证 - 不依赖 `npx skills` CLI,也不执行仓库中的任何安装脚本 - 部分仓库只在 README 中说明许可、没有 LICENSE 文件,这类技能无法安装(宁缺毋滥)