
1. 为什么我在三个 AI 编程工具之间来回折腾后最终用 skills.sh 收编一切先讲个真实场景。手头同时用 Claude Code、Cursor、Codex CLI 干活这是很多 AI 编程重度用户的常态。装好三个工具倒不费劲真正的麻烦在于每个工具都有自己的规则文件Claude Code 认CLAUDE.mdCursor 读.cursor/rules/下的.mdc文件Codex CLI 则看项目根目录的AGENTS.md。你以为是同一套工程规范结果要维护三份内容相似、格式各异的文件。改一个规则得手动同步三处漏掉任何一个对应的工具就会按旧规则干活。我最初的想法很简单搞一个脚本把一份 Markdown 复制到这三个位置。试了两周就意识到不对。Claude Code 的CLAUDE.md是纯 Markdown可以写很自然的指令Cursor 的.mdc文件需要在 frontmatter 里声明description、globs、appliesTo之类的元信息Codex 的AGENTS.md虽然也是 Markdown但它对结构、优先级、引用方式有自己的一套理解。硬复制不是不行但等于是把三套格式揉成一团最后写出来的规则文件既不够贴合平台语义又会因为格式差异反复折腾。后来找到 skills.sh 这个 CLI 工具思路一下就顺了。它做的不是简单的文件复制而是让你维护一份统一的技能定义再由工具本身负责把这份定义翻译成各个平台需要的格式。用了一段时间后我觉得这种一份源、多端编译的思路正好解决了多平台 AI 工具规则管理的核心痛点。这篇文章就把我踩过的坑、用下来的经验以及完整的操作流程整理出来给同样在多个 AI 编程工具之间切换的人做个参考。1.1 三套规则文件的精神分裂现场先列个表把各平台规则文件的核心差异摊开看平台默认规则文件位置格式规则粒度重要特点Claude Code项目根目录CLAUDE.mdMarkdown整文件读取支持项目级和用户级Markdown 章节越靠前越容易被模型关注Cursor.cursor/rules/目录下的.mdc文件Markdown frontmatter可按文件粒度控制frontmatter 里可以配globs指定作用范围alwaysApply控制是否总是生效Codex CLI项目根目录AGENTS.mdMarkdown整文件读取但支持层级引用也支持codex目录下的分文件配置适合大型项目拆分三套体系各有各的脾气。Cursor 的.mdc文件是最结构化的frontmatter 里写错了字段不会报错但规则可能静默失效这点后文会详细说。Claude Code 的CLAUDE.md则是自然语言优先你把它当作文档来写它读起来就很舒服但正因为自由度高团队里不同成员写出来的风格可能天差地别。Codex 的AGENTS.md目前越来越像一种标准——很多其他工具也开始兼容它但它对嵌套、引用的解析又与 Claude 不完全一样。1.2 一次真实改动引发的连锁事故让我痛下决心找解决方案的是一次很低级的错误。项目里原来的规则是提交代码之前必须跑测试某天负责人说改一下措辞把必须跑改成变更涉及核心模块时必须跑全量测试只改样式时允许只跑 lint。我在CLAUDE.md里改完顺手提交了事。第二天同事用 Cursor 打开项目AI 助手还在按旧规则办事他按照旧规则理解代码给出的重构建议里把可以跳过测试当成既定约束搞得我花了一个下午排查为什么测试覆盖面突然缩水。问题不在人的记忆而在规则文件的维护天然是分布式任务。三份文件三个位置没有一份权威副本任何一次局部改动都是在为未来的不一致埋雷。我当时想的很简单能不能用一套命令让我只编辑一份源然后一键同步到所有平台skills.sh 就是冲着这个诉求来的。2. skills.sh 的统一技能格式与多端适配机制它凭什么能当中央厨房把 skills.sh 想成一个中央厨房可能不准确更合适的比喻是编译管道。它先读取你定义的一份结构化的技能描述文件然后根据目标平台的配置格式差异生成对应的规则文件写入各自的目录。整个过程是单向的skills.yaml是源头CLAUDE.md、.cursor/rules/*.mdc、AGENTS.md是产物。你不需要直接手改产物即使手改了下次同步也会被覆盖。2.1 一份技能定义长什么样一个最小化的技能文件大概是下面这样project: ts-backend-ai-guide vars: language: TypeScript test_command: npm test skills: code-review: about: 代码评审的重点关注项 applies_to: [claude, cursor, codex] content: | # Code Review Rules 优先检查安全问题和数据校验 任何涉及数据库变更的逻辑必须显式说明会影响哪些表 Promise 必须处理 rejection不允许静默吞错。 测试豁免仅当改动为纯类型调整或注释变更时可跳过全量测试。 全文引用项目语言{{ language }} 提交前必须执行{{ test_command }}拆解一下结构project技能库所属项目的描述信息会作为规则文件的元信息写入产物。vars变量区。文件里用双花括号{{ }}引用的地方在同步时会被替换成真实值。这个机制的价值后面单独讲。skills真正的技能列表。每个技能有about说明、applies_to适用平台列表、content规则正文。content支持多行字符串内部写的是 Markdown将来同步到哪个平台skills.sh 会尽量保留 Markdown 语义。2.2 平台适配层是怎么工作的每个平台的生成器都可以看作一个独立的渲染器。skills.sh 在做sync时会做这么几件事解析skills.yaml校验 YAML 结构和字段合法性。根据applies_to判断当前技能要不要落到某个平台。读取项目里已有的目标文件比如已有CLAUDE.md把不属于 skills.sh 管理的历史内容保留下来只更新由它托管的那一段。按平台的格式规范渲染成最终文本写回对应文件。以 Cursor 为例它把规则拆成多个.mdc文件。skills.sh 会为每个技能生成一个.cursor/rules/your-skill-name.mdc文件并在 frontmatter 里写入必要的元信息--- description: code-review globs: **/*.ts alwaysApply: true --- # Code Review Rules ...Claude Code 和 Codex 则不同它们读取的是单一 Markdown 文件。skills.sh 会把所有applies_to包含claude的技能合并渲染进CLAUDE.md把这个文件做成一个标准 Markdown 文档同理codex的技能合并成AGENTS.md。合并的时候还会插入一段管理标记方便下次同步时定位哪些内容是 tools 生成的。2.3 为什么编译比复制靠谱很多人第一反应是我不需要这么复杂的工具写个 shell 脚本把一份文件复制三份不就行了我最初也是这么干的。区别在于复制只能解决文件内容一致性问题解决不了格式差异问题。CLAUDE.md需要的是自然的语言流不应该出现 frontmatter.mdc文件必须有 frontmatter否则 Cursor 不识别AGENTS.md对层级和引用有自己的解析偏好纯复制过来的内容可能没有发挥它该有的检索效率。编译的优势还体现在改动规则时不用手动处理多个文件中的折叠关系。比如往code-review技能里加一条规则只需要改 YAML 里那一处然后skills sync—— 所有平台的产物都会更新。这种唯一事实来源的模式对多项目、多团队协作尤其重要。3. 安装、初始化与第一次同步15 分钟跑通完整链路的实操记录工具再怎么设计得巧上手如果太复杂还是会劝退大多数人。好在 skills.sh 的安装成本很低核心链路也不长。下面按我实际操作的顺序走一遍。3.1 安装三种方式任选skills.sh 提供了三种安装途径覆盖常见环境。我用 macOS直接走 Homebrewbrew install skills-sh/tap/skillsLinux 环境下官方更推荐的是用预编译二进制curl -sSf https://install.skills.sh | sh这个脚本会把二进制装到~/.local/bin并让它在当前 shell 生效。Windows 上可以用 Scoopscoop bucket add skills-sh https://github.com/skills-sh/scoop-bucket.git scoop install skills装完验证一下版本skills --version如果输出版本号说明装好了。注意安装脚本只是把二进制放到 PATH不会动你的任何项目文件。怕它改东西的话可以先在一个空白目录里做试验。3.2 初始化技能仓库进入一个实际项目目录执行skills init这个命令会做几件事检查当前目录有没有skills.yaml没有则创建一个带注释的模板创建.skills/目录用来放模板文件、本地缓存、同步状态记录扫描目录下是否已有CLAUDE.md、.cursor/rules/、AGENTS.md等文件并在.skills/state.json里记录现状。init只会初始化不会立即写入任何内容所以可以放心跑。初始化完成后先看一下生成的skills.yaml里有什么注释说明再删掉注释改成自己的规则。如果你只是想先体验可以直接用官方提供的一个示例项目git clone https://github.com/skills-sh/skills-demo.git cd skills-demo skills sync --dry-run3.3 写一个最小技能并同步到三个平台在skills.yaml里只写一个技能内容务求简单方便观察同步效果project: demo vars: owner: Team Bot skills: no-debug-log: about: 禁止遗留调试日志 applies_to: [claude, cursor, codex] content: | 禁止在提交代码中遗留 console.log、println、print 等调试日志。 如需临时调试请用日志库并标记 TODO。 项目负责人{{ owner }}保存后执行skills sync --previewpreview会打印出将要写入哪些文件、每个文件里将包含哪些内容但不会真的写入。看到输出里有CLAUDE.md、.cursor/rules/no-debug-log.mdc、AGENTS.md三个目标确认无误skills sync执行完打开这三个文件看一眼。你会在CLAUDE.md和AGENTS.md里看到统一的 Markdown 段落并在.cursor/rules/no-debug-log.mdc里看到带 frontmatter 的独立文件。至此完整链路已经跑通改 YAML、预览、同步、各平台生效。4. 日常维护里的差异化同一份技能在不同平台如何各取所需同步只是基础能力真正让 skills.sh 好用的是它处理差异化的方式。实际项目中三个平台的使用场景不完全一样Claude Code 多用于终端里的长链路重构Cursor 偏向交互式补全和局部编辑Codex CLI 在自动化流水线里跑任务比较多。同一套规则硬性统一反而别扭。4.1 用条件标记区分平台行为一个常见需求有些规则只对 Cursor 生效因为 Claude Code 和 Codex 根本用不到比如补全时不要重排 import 顺序这类 UI 层面的编辑器行为对 CLI 工具没有意义。skills.sh 的applies_to字段天然支持这种区分skills: editor-specific: about: 仅 Cursor 生效的编辑器行为约束 applies_to: [cursor] content: | 自动补全时不得重排 import 顺序 重命名符号时必须同步更新测试文件中的引用 禁止自动折叠超过 200 行的函数。同步后你会发现CLAUDE.md和AGENTS.md里完全没有这段内容只有 Cursor 的.mdc文件里出现了它。这种按平台过滤的能力比把规则全部塞进所有文件然后靠模型自己判断要可靠得多。4.2 变量注入同一套规则不同环境变量多项目场景是变量注入最实用的地方。假设你有几个后端项目用的语言不同一个 Python、一个 Go。技能mock 接口时必须注明类型在两个项目里的表达方式略有差异——Python 项目要写typingGo 项目要写interface。在 skills.sh 里你不需要复制两份技能vars: language: Python mock_hint: 类型标注必须使用 typing 模块同一份技能文件拿到 Go 项目里把 vars 改一下再 sync输出就变成对应的语言约束。这个机制特别适合团队里的多项目模板。我个人的习惯是每个项目的skills.yaml只保留项目相关的vars和少数特色技能通用技能全放进全局模板里同步时用变量做差异化。4.3 平台级 override在统一与差异之间找平衡有时候你确实希望某个技能在大多数平台保持一致但某个平台上需要额外补充约束。skills.sh 提供了 overrides 机制skills: testing: about: 测试相关约定 applies_to: [claude, cursor, codex] content: | 修改核心逻辑时必须新增测试用例。 测试命令必须保持全绿。 overrides: codex: content: | 修改核心逻辑时必须新增测试用例。 测试命令必须保持全绿。 CI 流水线中若测试失败应立即切换到调试模式定位根因不能通过重跑掩盖问题。这个 override 会把 codex 平台的渲染内容替换成overrides.codex.contentclaude 和 cursor 仍然使用顶层content。它解决的是大多数一致、个别补充的需求不至于因为一个平台特殊就要复制整份技能。5. 实测一个月后我总结的四个容易踩的坑和对应排错方法工具用起来顺手是一回事真正放进工作流里哪些地方会出问题只有经过一段时间的实际使用才能暴露。下面这些坑不是看文档能提前避开的每一条都是我在真实项目里撞出来的。5.1 同步顺序先改源再 sync最后再提交最早期我犯过一个低级错误在skills.yaml里改了规则然后直接一起git add -A提交了。结果就是 YAML 更新了但生成的CLAUDE.md还是旧版——因为忘了skills sync。这个错误看起来蠢但很容易犯尤其是改完规则顺手就提交的肌肉记忆。正确的顺序永远是skills sync git add -A git commit -m chore: update code review rules如果嫌麻烦可以在skills.yaml所在目录配一个 Git hook提交前自动 sync。后面会说怎么配。如果你发现自己提交后某个平台的规则没有跟上游保持一致先检查一下是不是漏跑了sync。5.2 路径解析绝对路径 vs 项目相对路径content里如果写文件路径一定要用项目相对路径不要用绝对路径。Claude Code 在子目录启动时对绝对路径和相对路径的行为很不一样。实测中/Users/me/project/src/foo.ts这种绝对路径一旦换机器或者项目位置变化就会失效而且模型会拿着旧路径反复检索。相对路径src/foo.ts则没有这个问题。同样的道理也适用于.cursor/rules/里的globs字段# 推荐 globs: src/**/*.ts # 不推荐 globs: /Users/me/project/src/**/*.tsCursor 的 globs 如果写绝对路径在某些版本里不会报错但规则就一直不生效。5.3 Cursor 的 frontmatter 静默失效这是所有坑里最隐蔽的一个。Cursor 的.mdc文件 frontmatter 只支持特定字段具体字段名和取值在不同 Cursor 版本里还略有调整。早期我把alwaysApply写成了alwaysApply: true和appliesTo: always两种风格混用结果一部分文件生效一部分没有。问题是Cursor 并不会在你写错字段时给出任何提示——规则文件静静躺在.cursor/rules/里但 AI 完全不读它。排查办法是先用skills preview看生成结果再检查.mdc文件前几行cat .cursor/rules/no-debug-log.mdc正常输出应该包含--- description: no-debug-log globs: **/* alwaysApply: true ---如果看到description为空或者globs字段缺失基本就是生成器版本和当前 Cursor 版本不兼容。这时升级 skills.sh 并重新 sync 即可。更稳妥的方案是在技能的content开头把作用范围用 Markdown 注释写清楚这样即使 frontmatter 失效至少规则正文里还有提示信息。5.4 团队协作场景下的覆盖冲突多人同时在一个项目里维护规则最容易出现的是覆盖冲突。假设 A 在本地改了skills.yaml并 sync生成了新的AGENTS.mdB 也改了skills.yaml但他没拉到 A 的修改直接同步把 A 的部分改动覆盖掉了。这个问题在 Git 合作中很难完全避免只能通过流程来缓解skills.yaml必须走代码评审不要直接推到主分支生成的CLAUDE.md、.cursor/rules/、AGENTS.md可以纳入版本管理但要约定由sync统一生成禁止手改提交前用skills list --diff之类的命令确认本次改动影响了哪些平台。我现在的做法是在 CI 里加一道检查如果发现 YAML 和生成文件不一致就让流水线失败。这样所有改动必须先过一遍 sync才能合并进主线。6. 让 skills.sh 真正融入工作流的几个小技巧工具链这种东西能不能坚持用下去往往取决于它跟现有工作流贴合得紧不紧密。最后分享几个我用起来很顺手的小技巧。6.1 把高频技能固化成模板如果你经常要新建项目可以把通用技能抽成模板skills init的时候直接带上skills init --template gh:skills-sh/base-node-server模板里可以预设网络安全基线、提交信息规范、测试要求、环境变量命名规范等。这样新项目一开始就有一份比较像样的规则体系而不是从零开始写。我自己的模板里放了一套安全生产基线包含认证鉴权、日志脱敏、依赖审查三块内容新项目初始化后基本不用再改就能直接约束住 AI 工具的行为。6.2 用 Git Hook 自动同步减少手工负担前面说的先 sync 再提交配置成 hook 之后就不用操心了。在项目.git/hooks/pre-commit里写入#!/bin/bash if command -v skills /dev/null 21; then skills sync /dev/null 21 || echo skills sync failed fi exit 0并给它加执行权限chmod x .git/hooks/pre-commit这样每次git commit之前skills.sh 都会自动把 YAML 里的最新内容同步到各个平台文件。如果 YAML 没改动sync 会很快结束不会对提交速度造成什么影响。如果你用了团队级配置可以把这个 hook 的安装命令写进项目文档或者在skills init的时候自动生成。6.3 从 0 到 1 建立自己的技能库建议分三步走想要让这套体系真正发挥价值不建议一上来就试图穷举所有规则。我建议的顺序是第一步先只维护一个项目里的 3 到 5 条核心规则比如禁止调试日志变更必须补测试数据库变更必须显式说明影响。用一两周时间观察 AI 工具是否稳定遵守。第二步在确认核心规则稳定生效后把项目里遇到的AI 反复犯的错沉淀成新技能。比如某次 AI 在修改代码时频繁引入类型错误就可以加一条修改类型定义时必须同步更新使用处的类型声明。这类规则最好一次只加一条观察效果后再加更多避免一次加太多导致模型上下文过于拥挤。第三步当多个项目都用同一套规则后把它们抽成通用模板用变量区分项目差异。到这一步你的技能库就从一个项目的零散配置变成可以复用的组织级资产了。我个人在实际使用中最深的体会是skills.sh 的价值不在于自动生成文件这个动作本身而在于它逼着你把规则结构化、把来源集中化。过去我依赖在 AI 工具对话框里临时打字纠正它的方式对话框一关约束就消失现在所有约束都以技能文件的形式固化下来而且一次修改、全局生效。这种规则可版本化、可评审、可历史回溯的工作方式对我来说比任何 AI 模型本身的进步都更管用。如果你也同时有几个 AI 编程工具要伺候不妨花一个下午把 skills.yaml 搭起来体验一下只改一处到处生效的清爽感。