Cherry Studio Skills 治理实战:.agents/skills 单一事实来源、白名单同步与校验机制
【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio
本文围绕 Cherry Studio 仓库内.agents/skills目录的治理规范展开:如何新增一个 Skill、命名规则约束、public-skills.txt白名单如何驱动.gitignore生成与 Claude 侧符号链接同步,以及pnpm skills:sync/pnpm skills:check两个脚本的完整校验逻辑。读完本文,你可以独立完成仓库级 Skill 的创建、登记与 CI 合规校验,并理解该机制的源码实现细节。
单一事实来源:.agents/skills 是仓库内 Skill 的唯一维护位置
Skills 管理说明 开篇就确立了核心原则:.agents/skills/是仓库内 skills 的唯一维护来源(single source of truth)。所有需要被仓库跟踪、被 CI 校验、被同步到 Claude 目录的 Skill,其真实文件都必须落在这个目录下;其他位置(如.claude/skills/)只存放指向它的符号链接。
从源码结构看,这一原则在 skills-common.ts 中被显式编码为一组路径常量:
export const AGENTS_SKILLS_DIR = path.join(ROOT_DIR, '.agents', 'skills') export const CLAUDE_SKILLS_DIR = path.join(ROOT_DIR, '.claude', 'skills') export const AGENTS_SKILLS_GITIGNORE = path.join(AGENTS_SKILLS_DIR, '.gitignore') export const CLAUDE_SKILLS_GITIGNORE = path.join(CLAUDE_SKILLS_DIR, '.gitignore') export const PUBLIC_SKILLS_FILE = path.join(AGENTS_SKILLS_DIR, 'public-skills.txt')即整个治理体系围绕五个对象运转:两个 Skill 根目录、两个自动生成的.gitignore、一份公共白名单文件。当前仓库中.agents/skills/下已经存在 8 个公共 Skill(gh-create-pr、prepare-release、create-skill、gh-create-issue、gh-pr-review、vercel-react-best-practices、cherry-pr-test、cherry-electron-dev),它们的具体内容可通过 public-skills.txt 逐一查看。
新增 Skill 的完整流程
文档给出了四步标准流程,逐条展开如下。
第 1 步:创建技能目录
在.agents/skills/<skill-name>/下创建新目录。目录名即 Skill 名,必须满足命名规则(下文详述)。
第 2 步:编写 SKILL.md
每个 Skill 目录必须包含SKILL.md,其结构由两部分组成:
- YAML frontmatter:至少包含
name和description两个字段; - 正文:精简的流程说明。
以仓库内的 gh-create-pr/SKILL.md 为例,其 frontmatter 形如:
--- name: gh-create-pr description: Create or update GitHub pull requests using the repository-required workflow and template compliance. Use when asked to create/open/update a PR ... ---description字段写得非常具体:说明该 Skill 何时应被触发("Use when asked to...")、以及触发后 Agent 必须执行的完整动作序列。这是 Skill 能否被 AI 助手正确路由的关键。
Skill 目录内还可以放补充材料,例如gh-create-pr附带 references/ 参考资料、cherry-electron-dev附带 references/electron-instance.md。这些引用文档不会被单独同步,而是随整个目录通过符号链接整体暴露给 Claude。
第 3 步:(可选)Codex UI 元数据
如需为 Codex UI 提供展示元数据,可在 Skill 目录下添加agents/openai.yaml。以 gh-create-pr/agents/openai.yaml 为例:
interface: display_name: "Create GitHub PR" short_description: "Create PRs with required template compliance" default_prompt: "Create a pull request for my current branch using the repository template workflow."该文件仅用于界面展示(显示名、短描述、默认提示词),与 Skill 功能本身解耦,属于可选项。
第 4 步:登记到公共白名单
若该 Skill 需要作为仓库公共 Skill 被 Git 跟踪,需将<skill-name>追加到 .agents/skills/public-skills.txt。只有完成这一步,后续的skills:sync才会为它生成.gitignore例外规则和 Claude 侧符号链接。
命名规则及其源码级约束
文档规定:Skill 名称仅使用小写字母、数字和连字符(-),并优先使用简短、动作导向的名称(如gh-create-pr)。
这条规则不只是文档约定,而是被 skills-common.ts 中的正则硬性执行:
const SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/listSkillNames()在解析public-skills.txt时对每一行执行多重校验,任何一条失败都会直接抛错终止流程:
- 空行与以
#开头的注释行被跳过; - 行内注释被显式禁止——若某行在名称之后还出现
#,会抛出inline comments are not allowed ... put comments on the previous line,即注释必须单独成行,不能写在行尾; - 不符合
SKILL_NAME_PATTERN的名称(大写、下划线、前导/尾随连字符等)会被判定为invalid skill name; - 重复登记同一 Skill 名会报
duplicate skill name。
解析结果最终按字母序排序(names.sort((a, b) => a.localeCompare(b)))后返回,这保证了后续生成的.gitignore例外规则顺序稳定、diff 可预测。
Claude 兼容:符号链接同步机制
每个新增的公共 Skill,需要执行同步命令:
pnpm skills:sync对应 package.json 中的脚本定义:
"skills:sync": "tsx scripts/skills-sync.ts", "skills:check": "tsx scripts/skills-check.ts"同步脚本做了什么
sync 脚本 做两类事情,且都具备幂等性(内容无变化时不写盘):
1. 重新生成两个.gitignore。由 buildAgentsSkillsGitignore / buildClaudeSkillsGitignore 按白名单构建:
# AUTO-GENERATED by `pnpm skills:sync`. # Do not edit manually. * !.gitignore !README*.md !public-skills.txt !cherry-electron-dev/ !cherry-electron-dev/** ...(每个白名单 Skill 一组例外)策略是"默认全部忽略,仅放行白名单":.agents/skills/.gitignore先*忽略整个目录,再对.gitignore、README*.md、public-skills.txt以及每个白名单 Skill 目录(!name/与!name/**)逐一放行;.claude/skills/.gitignore同理,但放行的是符号链接条目本身(!name)。当前仓库中的 .agents/skills/.gitignore 与 .claude/skills/.gitignore 就是该机制的生成产物,与 8 个公共 Skill 一一对应。
2. 创建/修正 Claude 侧符号链接。核心函数ensureClaudeSkillSymlink的逻辑是:
- 确认
.agents/skills/<name>源目录存在,缺失则直接抛错; - 期望的链接目标是相对路径
../../.agents/skills/<name>(相对于.claude/skills/); - 若
.claude/skills/<name>已是符号链接且指向正确,则跳过(幂等); - 若已存在但指向错误,或是普通目录/文件,先
fs.rmSync递归删除,再用fs.symlinkSync重建指向../../.agents/skills/<name>的符号链接。
也就是说,skills:sync会自动创建/更新.claude/skills/<skill-name>为指向../../.agents/skills/<skill-name>的符号链接——Claude 读到的 Skill 内容与.agents/skills源目录永远是同一份文件,不存在内容漂移问题。
脚本结束后按结果输出skills:sync up-to-date (N public skills)或逐项列出更新的文件清单,方便在 CI 日志中确认变更范围。
白名单跟踪规则与 skills:check 校验
公共白名单由 public-skills.txt 定义,当前实际内容为:
# Public skills tracked by skills:sync and skills:check. # One skill name per line. gh-create-pr prepare-release create-skill gh-create-issue gh-pr-review vercel-react-best-practices cherry-pr-test cherry-electron-dev文档对登记方有三条硬性要求,均与源码行为严格对应:
- 写入该文件的 Skill 会同步到两个
.gitignore——即上一节所述的两组自动放行规则; - 私有/仅本地使用的 Skill 不应写入白名单——不登记意味着
.agents/skills/.gitignore的*规则会将其整体忽略,Git 不会跟踪;同时skills:check会把已跟踪的非白名单文件判为违规(见下文); - 每行只写一个 Skill 名,注释行必须以
#开头,不能写行尾注释——对应listSkillNames()的解析与报错逻辑。
更新public-skills.txt后依次执行:
pnpm skills:sync # 重新生成 .gitignore 与符号链接 pnpm skills:check # 校验一致性skills:check 的四层校验
check 脚本 是这套治理机制的"守门员",main()依次执行四类检查,任一失败即打印全部错误并以退出码 1 终止:
- Gitignore 时效性:用白名单重新构建期望内容,与磁盘上的 .agents/skills/.gitignore、.claude/skills/.gitignore 逐字节比对;不一致即报
is out of date (run pnpm skills:sync)。 - 源目录存在性:白名单中每个 Skill 都必须有对应的
.agents/skills/<name>目录,缺失直接报错。 - 符号链接有效性:
checkClaudeSkillSymlink用lstatSync检查.claude/skills/<name>——它必须是符号链接(而非普通目录或文件),且readlinkSync读出的目标必须精确等于../../.agents/skills/<name>。 - Git 跟踪范围不越界:
checkTrackedFilesAgainstWhitelist执行git ls-files -- .agents/skills .claude/skills,把 Git 实际跟踪的每个文件与白名单比对。允许跟踪的仅限:两侧的.gitignore、README*.md(含README.zh.md这类带语言后缀的变体,由正则^\.agents\/skills\/README(?:\.[a-z0-9-]+)?\.md$匹配)、public-skills.txt,以及白名单 Skill 目录下的文件。出现白名单外的已跟踪文件会报tracked file is outside public skill whitelist。
校验通过时输出skills:check passed (8 public skills)。
值得注意的是,skills:check已接入 CI 基础检查:package.json 中ci:basic-check脚本串联了 lint、格式、类型检查、i18n 检查以及pnpm skills:check、docs:check。这意味着 Skill 白名单与仓库实际跟踪状态的一致性是每个 PR 都要过的关卡,而不仅仅是本地约定。
Windows 兼容性:符号链接的前置配置
由于本项目使用符号链接同步 AGENTS.md、skills 等文件,Windows 开发者需要手动启用符号链接支持,文档给出两步路径(任选其一)加两步收尾:
- 启用开发者模式(设置 → 更新和安全 → 开发者选项);或
- 通过本地安全策略(
secpol.msc)授予SeCreateSymbolicLinkPrivilege权限。
然后:
配置 Git以创建符号链接:
git config --global core.symlinks true重新克隆仓库(或执行
pnpm skills:sync),让 Git 按符号链接物化.claude/skills/下的条目。
从实现角度看这一步的必要性:ensureClaudeSkillSymlink与checkClaudeSkillSymlink都依赖fs.symlinkSync/fs.lstatSync/fs.readlinkSync,在未开启core.symlinks的 Windows 检出中,符号链接条目可能被还原为普通文件,此时skills:check会明确报出must be a symlink, not a file (run pnpm skills:sync)一类的错误,提示重新同步。
小结
Cherry Studio 的 Skill 治理用一份白名单(public-skills.txt)加两个幂等脚本(skills:sync/skills:check)实现了一套低成本的多人协作约束:真实内容只维护在 .agents/skills/ 一处,Claude 侧通过符号链接零拷贝共享,Git 跟踪范围由自动生成的.gitignore白名单精确控制,而skills:check的 gitignore 比对、符号链接比对、git ls-files越界检查三道防线保证了任何漂移都能在 CI 中被拦截。新增 Skill 时只需记住闭环动作:建目录 → 写SKILL.md(含name/descriptionfrontmatter)→ 登记白名单 →pnpm skills:sync→pnpm skills:check通过后提交。
【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考