上周我差点在三个工具窗口之间被逼疯。一边开着 Cursor 写日常代码,一边挂着 Claude Code 跑长链路过任务,另一边还留着 Antigravity 玩图形化 agent 工作流,三个都得用,三个都得装 Skills。结果我发现,自己居然还在手动拷贝同一个SKILL.md,改完一处忘了另一处,然后眼睁睁看着 agent 用旧技能跑出结果。忍无可忍之后,我干脆写了个开源小工具把这问题治了:所有 skill 收进一个 Git 仓库,再用脚本统一分发到 Cursor、Claude Code 和 Antigravity 各自识别的目录。今天就把痛点和思路拆开讲,顺便把可抄作业的脚本也一起放上来。
1. 先聊痛点:你的 Skills 到底碎成了几块?
1.1 同时装三个工具的人,到底图什么
先说说我为什么这么折腾。Cursor 最适合日常写代码,补全体验确实一流,界面也顺手,大部分时候我拿它当主力编辑器;Claude Code 是终端里的 agent,长链路任务特别能打,我经常让它一口气把测试、重构、文档全做了,效率真的高;Antigravity 这边玩的是 agent tools 和设备整合,遇到前端交互、多步骤自动化任务时,表现让人眼前一亮。三个工具分工明确,我是真的哪个都舍不得卸。
既然都不卸载,问题就来了:个性化能力,也就是 Skills,其实是跟着工具走的。一个前端调试 skill,我在 Claude Code 里调好,到 Cursor 里不能直接用,到 Antigravity 里还得再配一遍。最原始的方式就是复制粘贴,于是我开始在~/.claude、~/.cursor、~/.antigravity这几个目录之间来回横跳。
后来发现,这个场景并不是少数人遇到。身边不少同时折腾 Cursor 和 Claude Code 的朋友,都问过“skills 目录在哪里”“怎么才能共用”。实际上这三家对“技能”的概念已经越来越像:基本都是SKILL.md加资源文件,再加一段 YAML frontmatter。可正因为“像但不等同”,手动同步的体力活才格外恶心。
1.2 手动拷贝的三大坑
我手动拷了大概两周,踩到三个特别实在的坑,拿出来给大家排雷。
第一个坑是版本不同步。Git 仓库里维护一份 skill,改了 description 忘了同步到 Cursor,结果同一个 agent 行为,在 Claude Code 里是新逻辑,在 Cursor 里还是旧逻辑。排错的时候你会怀疑是不是模型傻了,其实只是两边文件不一致。
第二个坑是目录结构不统一。每个工具的加载目录都不一样,有的认全局、有的认项目级,有的要求必须是skills/<skill-name>/SKILL.md这样的嵌套,有的把 skill 直接塞进 rules 目录。手动复制的时候,很容易把文件放错层级,工具完全不认,但你根本不知道它为什么没加载。
第三个坑是换电脑迁移。本地调好的 skill,换台机器就全部消失。每次重装系统、换笔记本,就等于从头开始考古,到处翻聊天记录找回之前写的版本。时间成本高得离谱。
除了这三个坑,还有一个隐形问题:skill 内容本身会在重复劳动中变形。你复制五次,可能第五次的文件跟第一次差了好几个空格、少了一段提示词,而 agent 对 skill 文本非常敏感。经常是同样的任务,换个工具跑出来的表现差一个档次,最后你根本分不清是模型差异还是配置差异。
1.3 常见的几种“伪解决方案”
有人可能会想:那我用网盘把整个目录同步了不就行?我试过,不行。直接把~/.claude、~/.cursor拖进云盘同步,会连日志、缓存、临时文件一起同步,一不小心还容易把两个工具的配置互相污染。网盘占内存不说,冲突处理还特别恼人。
有人会想靠工具自带的云同步。Cursor 有账号级同步,Claude Code 也有团队配置,但他们各自同步的只是自家那套生态,不会帮你把一个 skill 分发到另外两个产品。真要在这几个生态里手工维护内容,大概比直接复制文件还麻烦。
还有人用“一次性脚本把文件复制过去”,这个思路接近正解。但很多脚本写得太硬编码,路径写死、没有任何回滚机制,跑一次可能把 Cursor 现有的 rules 直接覆盖掉,风险不低。真正好用的方案,得满足四个条件:有单一数据源、支持软链或复制两种模式、能留下备份、能一键回滚。下面这套开源方案,就是奔着这四个点去的。
2. 一套统一管理思路:把 Skills 当代码来管
2.1 单一数据源:skill 就是你的“代码依赖”
既然我们天天用 Git 管代码,为什么没人用 Git 管 skill?其实完全可以。我的做法是在本机建一个~/.skills目录,把它做成一个 Git 仓库,里面每个子目录就是一个独立 skill,统一结构:
.skills/ frontend-debug/ SKILL.md resource/ ... screenshot-compare/ SKILL.md script/ ...每个 skill 的核心是SKILL.md,frontmatter 里写 name、description,正文写具体任务步骤和约束,其他辅助文件按需放。这样一套结构,既符合 Claude Code 官方对 skill 的约定,也能被 Cursor、Antigravity 的 agent 加载器容忍。
把 skill 当代码依赖管,最大的好处是“唯一权威版本”。任何时候想改,就去~/.skills里改,其他地方都是分发出来的副本或软链。这相当于给 agent 技能加了一层 git 历史:哪个版本改坏了,可以回滚;哪天 agent 行为突然异常,先看git diff。配置漂移是最容易让人崩溃的,仓库把起点固定住,就算某个工具抽风给你的 skill 目录塞了一堆额外文件,你也知道源头在哪。
2.2 三个工具到底从哪里读 Skills
仓库结构定好后,剩下就是要把 skill 分发到三个工具各自能识别的位置。这里我把目前常见的路径整理成了一张表,以我用的版本和你看到的官方文档为准,不同小版本可能有差异:
| 工具 | 全局加载目录(常见) | 项目级加载目录(常见) | 入口文件 |
|---|---|---|---|
| Claude Code | ~/.claude/skills | .claude/skills | SKILL.md |
| Cursor | ~/.cursor/skills(较新版本) | .cursor/skills | SKILL.md |
| Antigravity | ~/.antigravity/skills或 tools 目录 | .antigravity/下约定目录 | SKILL.md或工具清单 |
这里要特别说明:Claude Code 的~/.claude/skills和项目.claude/skills是比较明确的结构,官方已经把它当作标准能力;Cursor 在较新版本里支持.cursor/skills,老版本主要靠.cursor/rules,所以如果你用的版本比较旧,建议把 skill 的核心内容转成一份 rules 文件做兼容;Antigravity 的目录约定在社区里还没完全统一,我按~/.antigravity/skills来配置,如果官方后来更新了,改一下脚本里的路径就行。
记住一个关键点:入口文件一定要叫SKILL.md,并且放在skills/<skill-name>/下面。少一层,工具经常就不认。不少人“复制了但没生效”的案例,十有八九是路径层级不对。
2.3 为什么最终选择写一个开源分发脚本
目录映射明确后,按理说手动复制也能做,但我还是选择把它做成开源脚本来管理,原因有三个。
第一个原因是“增量分发”。有些 skill 是 Claude Code 专属的,不一定要分发给 Cursor;有些是针对前端项目的,团队里用 Antigravity 的人压根不需要。手动复制做不到按需过滤,脚本可以在分发前做一次匹配。
第二个原因是“可回滚”。直接复制会覆盖目标目录里的同名文件夹,而且没有备份。脚本在发现目标里存在同名真实目录时,会先把它改名成.bak.时间戳再创建软链。出问题想回滚,直接删掉软链、把.bak改回原名就行。
第三个原因是“可复用”。我不希望同样的事情在每台电脑、每个成员那里重复造轮子。写成开源脚本后,换新电脑先 clone 仓库,再跑一次同步,所有 skill 全部就位。这也符合“把配置工程化”的思路:凡是做过一次以上,就值得自动化。
3. 抄作业:skill-sync 分发脚本实战
3.1 初始化 Skill 仓库结构
开始之前,先把仓库建好。打开终端,执行:
mkdir -p ~/.skills cd ~/.skills git init mkdir -p frontend-debug screenshot-compare docs然后往每个目录里放SKILL.md。一个最小可用的SKILL.md长这样:
--- name: frontend-debug description: 用于定位前端页面样式和交互问题的调试技能。当用户提到页面错位、点击无反应、样式异常时使用。 --- # 前端调试流程 1. 先检查浏览器控制台是否有报错。 2. 打开对应组件代码,确认 props 是否正确传递。 3. 若为样式问题,使用截图对比定位差异。 4. 修复后运行现有测试并汇报改动。frontmatter 里name和description是最低要求,description 写得越清楚,agent 在任务匹配时越容易命中。写完 SKILL.md,再补点辅助文件,比如测试脚本、截图资源。然后提交:
git add . git commit -m "init skills"我现在习惯把仓库托管在远端,比如 GitHub 私有仓库,这样多设备同步又多了道保障。
3.2 分发脚本:一键同步到 Cursor、Claude Code、Antigravity
仓库建好后,写一个skill-sync.sh。下面这个版本我一直在用,代码很短,但把备份、幂等、dry-run 这些关键点都覆盖了:
#!/usr/bin/env bash # skill-sync: 一键把 ~/.skills 中的所有 skill 分发到各工具目录 # 用法: # bash skill-sync.sh 正常同步 # DRY_RUN=1 bash skill-sync.sh 只打印将要做的事 set -euo pipefail SKILL_HOME="${SKILL_HOME:-$HOME/.skills}" DRY_RUN="${DRY_RUN:-0}" TARGETS=( "$HOME/.claude/skills" "$HOME/.cursor/skills" "$HOME/.antigravity/skills" ) for target in "${TARGETS[@]}"; do mkdir -p "$target" done if [[ ! -d "$SKILL_HOME" ]]; then echo "找不到 skill 仓库: $SKILL_HOME" >&2 exit 1 fi for skilldir in "$SKILL_HOME"/*/; do [[ -d "$skilldir" ]] || continue name="$(basename "$skilldir")" for target in "${TARGETS[@]}"; do link="$target/$name" if [[ "$DRY_RUN" == "1" ]]; then echo "[dry-run] $skilldir -> $link" continue fi if [[ -e "$link" && ! -L "$link" ]]; then mv "$link" "${link}.bak.$(date +%s)" echo "[backup] $link 已被备份" fi ln -sfn "$skilldir" "$link" echo "[synced] $name -> $link" done done解释几个关键点。
set -euo pipefail:保证脚本在遇到未定义变量或管道失败时直接退出,不会假装成功。DRY_RUN:我建议第一次跑之前先DRY_RUN=1 bash skill-sync.sh看看将要创建哪些软链。- 备份逻辑:如果目标目录已经存在一个真实目录,比如你手动拷过一个同名 skill,脚本不会直接删,而是先备份成
.bak.时间戳,再建立软链。这条非常关键,能救回不少手滑操作。 ln -sfn:-f强制覆盖,-n把最后一个参数当作普通文件而不是目录,避免软链到目录内部。
跑完之后,可以用ls -l看到各工具目录里多了一堆指向~/.skills的软链。到这里,分发已经完成。
3.3 反向收集:临时改的技能怎么收回仓库
正常流程是“只在仓库改,然后向外分发”。但实际使用中难免有这种情况:你在某个工具里临时调了个 skill,效果很好,想留进仓库。这时候再手写一份就重复劳动了。我加了一个skill-collect.sh,把工具目录里的改动同步回仓库:
#!/usr/bin/env bash # skill-collect: 把工具目录中的 skill 收集回 ~/.skills set -euo pipefail SKILL_HOME="${SKILL_HOME:-$HOME/.skills}" collect_from() { local src="$1" [[ -d "$src" ]] || return 0 for skilldir in "$src"/*/; do [[ -d "$skilldir" ]] || continue local name name="$(basename "$skilldir")" if [[ "$skilldir" -ef "$SKILL_HOME/$name" ]]; then # 本身已经是软链指向仓库,无需收集 continue fi echo "[collect] $skilldir -> $SKILL_HOME/$name" mkdir -p "$SKILL_HOME/$name" cp -a "$skilldir"/. "$SKILL_HOME/$name"/ done } collect_from "$HOME/.claude/skills" collect_from "$HOME/.cursor/skills" collect_from "$HOME/.antigravity/skills"这里用-ef判断是不是同一个 inode,如果是软链指向仓库,就跳过;否则才复制。收集完记得git diff检查一下,别把工具的自动生成文件收进去。我一般只在“临时改动确认要留”的时候用,日常还是坚持“仓库为准”。
3.4 怎么确认三个工具真的识别到 Skills
同步完,不能光看命令行说成功就完事,得真的让工具加载出来才算数。我的验证顺序是:
- Claude Code:启动后使用
/skills或官方 skill 管理入口查看,正常会列出所有已加载 skill;或者直接打一句相关的任务描述,看 agent 有没有触发对应 skill。 - Cursor:打开 agent 面板,找 skills 列表;如果列表里没出现刚同步的名字,先退出重启,检查路径是全局还是项目级。
- Antigravity:在 agent 界面找 tools / skills 入口,确认 skill 出现在可调用列表里。
如果某个工具死活不识别,最快排查方法就是看日志。Claude Code 可以用--debug模式启动,Cursor 在输出面板里搜索 skill,Antigravity 则看它导出的事件日志。日志里一般会写明“skill not found”还是“skill loaded”,这样就能定位是不是路径或 frontmatter 的问题。
我对三个工具的实测结论是:把 SKILL.md 放对层级、frontmatter 完整,几乎都能识别。识别不到十有八九是版本差异或项目级、全局级路径搞混。
4. 真实踩坑记录与问题速查
4.1 软链不生效:工具有时候会“跳过”符号链接
这个坑我印象最深。最开始我兴冲冲地把所有 skill 都软链过去,Claude Code 很给面子,全部识别;但 Cursor 那边死活不认。后来查半天,发现它启动时确实会跳过一部分符号链接,或者只扫真实目录。遇到这种工具,软链方案就不适用。
解决办法是改成复制模式。把ln -sfn那行替换成:
if [[ -d "$link" || -L "$link" ]]; then rm -rf "$link" fi mkdir -p "$link" cp -a "$skilldir"/. "$link"/代价是每次同步都会复制一遍文件,但换来更高的兼容性。我现在的做法是“默认软链,遇到不识别再切换复制”,在脚本里放一个SYNC_MODE环境变量,默认symlink,可以改成copy,方便适配不同机器的需求。
4.2 全局 vs 项目级 skill,优先级和冲突怎么处理
另一个高频坑是优先级。工具通常会优先加载项目目录下的 skill,全局目录作为兜底。如果你全局有一个frontend-debug,项目里又放了一个同名 skill,工具基本会使用项目级的。这个设计本身合理,但容易造成“我改了全局,项目里却没变化”的假象。
我的建议是:默认把所有公用的 skill 放全局,项目特化的技能放项目目录;同名 skill 尽量避免。如果项目确实需要不同版本,就在项目目录维护一个增量版本,里面只写覆盖差异,而不是把整份 SKILL.md 拷过去。一个 agent 同一任务如果被两个相似 skill 影响,很容易做出混合行为,排查起来非常痛苦。
4.3 一个 SKILL.md 怎么做到三家通吃
技能文件能不能三个工具共用,关键在 frontmatter。Claude Code 官方要求的name和description是基础;Cursor 和 Antigravity 对这两个字段也支持,但会分别加自己的扩展字段。
稳妥策略是“最小公共 frontmatter”。SKILL.md 里只放 name、description 和正文,其他扩展配置丢到附加文件,比如cursor.extra.md、antigravity.tool.json,不进 SKILL.md 主体。这样能避免某个工具遇到不认识的字段时报解析错误。我在社区里看到过很多 skill 包,前几行 YAML 塞了一堆模型专属参数,换工具就废掉,这种做法我不推荐。
还有一个容易被忽略的点:SKILL.md 正文里尽量不要写死“你是 Claude”或“你是 Cursor”这类平台暗示。agent 在多工具间切换时,这会影响表现,而且也不是 skill 该承担的功能。保持纯技能描述,才是跨工具的最好姿势。
4.4 多设备同步:git pull 之前先把工具关了
换电脑同步,我踩过最搞笑的一个坑:在笔记本上git pull拉取最新 skill,结果 Cursor 还开着,编辑器把某些 skill 文件的锁握住了,导致 git 报一堆“unable to update”错误。后来我固定成流程:先退出所有 AI 编程工具,再 pull,再跑同步脚本,最后打开工具验证。
另一个建议是把同步脚本放到 PATH 里,命名清晰一点。我的 shell 里直接配了一个 alias:
alias skill-sync='cd ~/.skills && git pull --rebase && DRY_RUN=0 ~/.skills/tools/skill-sync.sh'每次重装系统后,只要先装 git,再从远端 clone 一下仓库,执行一次同步,所有 skill 就位,十分钟内能从零开始干活。
4.5 常见问题速查表
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| skill 不出现在列表 | 目录层级不对 | 检查skills/<skill-name>/SKILL.md这个结构 |
| 改了仓库但工具无变化 | 工具缓存或者软链未跟随 | 重启工具进程再验证 |
| 多设备行为不一致 | 忘了同步 git | 先 pull 再 sync |
| 云盘同步产生大量冲突 | 工具元数据混入共享盘 | 不要把整个 home 目录放进云盘 |
| Antigravity 无法登录或加载 | 账户资格或支持范围问题 | 去官方渠道确认支持列表,用合规方式等开放 |
| 工具不认软链 | 扫描器跳过符号链接 | 切换SYNC_MODE=copy |
Antigravity 那个问题,我要多说一句:如果遇到账户资格或地区支持的提示,别抱着侥幸心理找捷径,老老实实看官方支持范围和申请流程,等开放后再用。工具生态本身是好的,没必要为了早用几天去冒违规风险。
5. 进阶玩法:这套方案还能怎么延伸
5.1 给 Skill 做版本管理和标签
用 Git 管理之后,你天然获得了版本管理能力。我建议每个稳定版本用 tag 标记,同时 SKILL.md 的 frontmatter 里加一个version字段:
--- name: frontend-debug description: ... version: 1.0.0 ---好处是:当 agent 行为突变,你可以先用git log --oneline -- frontend-debug/定位改动,然后git show <commit>看具体 diff,而不是在好几个工具目录里人工对比文件。有一次我就是靠这个定位到“某次把描述里的触发词改宽了,导致 agent 过度触发”的问题。
5.2 团队共享和三端 CR 流程
如果团队里有四五个人都折腾 AI 编程工具,这套仓库可以变成团队共享资产。每个人把技能 PR 进去,其他人 review 后合并,再各自拉取同步。我试过效果很好,但需要定规矩。
我的经验是维护一个sync.conf白名单文件,记录哪些 skill 分发到哪些工具。比如frontend-debug分发给三个工具,但某个内部调试 skill 只分发给 Claude Code。分发脚本读取这个配置,能避免把不适合的工具也给配一份。团队越大,这种“按工具裁剪”越重要。
另外可以加一个 git hook:push 之前自动跑一遍bash skill-sync.sh --dry-run,至少保证仓库里的目录结构是合法的。也能在 CI 里跑一个简单脚本,检查每个 skill 目录下有没有SKILL.md、frontmatter 里的 name/description 是否完整。这种机器检查比人工 review 靠谱得多。
5.3 从社区 Skills 包导入并统一管理
第三方社区已经有很多现成 skill 包,像 superpower skills、codex skills,以及各种垂直场景的 agent skills。我的建议是:不迷信“拿来即用”,而是下载后统一整理进~/.skills,再做一次适配。
具体流程:
- 下载社区 skill 包到临时目录,确认目录结构和 SKILL.md 存在。
- 把需要的子目录复制到
~/.skills下,按自己的命名规范命名,比如加前缀区分来源。 - 检查 frontmatter,把 name/description 改清晰,去掉不兼容字段。
- 跑一次
bash skill-sync.sh分发,到各工具里验证。
社区包常见问题是质量参差不齐。有的 skill 描述写得太泛,agent 压根不会触发;有的塞了过多平台特化内容,换工具就报错。所以我通常一周只挑一两个真正高频的技能导入,不追求把几百个 skill 全装进去。装太多反而会让 agent 在匹配时无所适从。
5.4 做成 CLI 或者 GUI 的扩展方向
如果你就是喜欢把方案打磨成工具,还能继续扩展:把skill-sync.sh换成 Python 实现,支持配置文件、支持目标目录增删,甚至做成一个带 TUI 的客户端。也可以给仓库加一个简单的 GitHub Action,每次合并后自动用缓存 runner 验证所有 skill 能被解析。
不过我自己的实际体验是,脚本工具做到“能用”就够了,别为了优雅而过度设计。同步这件事,本质是一个纯函数:从~/.skills输入,输出到 N 个目标目录。保持透明、可回滚,比写得花哨重要得多。
最后再分享一个小习惯:我现在的 skill 文件,从来不在任何工具的编辑器里直接改。不管多顺手,也忍住,统一回到~/.skills仓库里改,改完跑一次同步脚本。一开始会觉得多了一步,别扭;坚持一周后,你会发现“改了这边,那边没跟上”的焦虑彻底消失。电脑上永远只有一个地方需要维护,其他全是分发副本。如果你也同时用 Cursor、Claude Code 和 Antigravity,这套方案值得抄一遍。