1. 先别急着装技能理清多Agent多Skills到底乱在哪最近半年身边越来越多朋友开始同时用Claude Code、Codex、OpenCode这类AI编程Agent再加上Pi Agent、Hermes Agent这些偏对话和任务执行的智能体人手一套Skills已经成为常态。但问题也接踵而至每个Agent有自己识别技能的方式有自己存放技能文件的默认目录甚至连技能的称呼都不一样——有的叫Skills有的叫Commands有的叫Plugins。于是很快就会出现一种很尴尬的局面在Claude Code里调得好好的代码审查专家技能切到Codex环境下要么找不到、要么格式直接不认GitHub上淘来的Skill包解压之后不知道该往哪个文件夹放。我一开始也是这个状态电脑里散落着四五个Agent的配置目录每个目录里都堆着从不同地方下载的Skill文件乱到连自己都记不清哪个版本是新改的。后来每次开新项目都要花十分钟去找技能、试技能、修技能效率比不用技能还低。这篇文章想聊的就是我最终落地的一套简单方法——不依赖复杂的平台不引入额外的服务器核心就三件事统一目录、统一元信息、统一同步。这套方法我自己跑了两个月实测能在多个Agent之间复用同一批Skills改一次配置全端生效。在动手之前大家心里要先有个底所谓的简单方法不是去造一个新框架而是想办法把一个Agent的技能目录变成所有Agent都能读懂的公共资源。要做到这一点得先把每个Agent读取技能的原理搞清楚——至少搞到够用的程度。下文我会先用最少篇幅讲清楚为什么Skills会不通用然后给出目录结构、初始化清单、同步脚本和日常避坑这四块内容每块都是可以直接抄作业的。2. 为什么同一个Skill换个Agent就失灵三个必须接受的事实2.1 每个Agent的Skills本质上是提示词上下文的打包方式先说一个最基础但很多人误解的点所谓Skills本质上并不是独立的程序或插件它们大多是一组结构化的文本——通常是Markdown格式的指令说明、示例、约束条件有时候附带几个脚本文件用来在某些需要计算的场景里做辅助。Agent之所以能调用技能是因为框架约定了一个目录路径比如Claude Code默认去.claude/skills目录找Codex有自己的skills目录OpenCode则是.opencode/command这类路径。框架读到技能文件后会把文件内容当作上下文的一部分加载进对话窗口。理解了这一点就能明白为什么同一个Skill在另一个Agent里会失灵。原因很直白每个框架对技能文件的结构要求不同有的需要YAML格式的frontmatter来声明name和description有的只认纯Markdown的固定文件名还有的要求把脚本和文档分开放在指定子目录里。换个环境等于换了一套入场规则原来的文件格式不符合要求自然不会被加载。2.2 越重的技能越难跨Agent复用我在整理自己那堆技能时发现一个规律纯文档型的轻技能只有一份Markdown指令迁移起来几乎零成本顶多修改一下文件头格式而那些带了脚本、依赖特定运行时环境、甚至需要在项目里自动跑命令的重技能换到另一个Agent里往往不只是改改格式就能解决的脚本路径要改、依赖参数要对齐、输出格式还要重新适配。所以如果想要低维护地管理多Agent共享技能比较务实的策略是优先复用轻技能把重技能当作Agent专属能力不要强行追求全端覆盖。这一条放在选型阶段就能帮你省掉大量后续麻烦。当然如果你确实维护着几个重量级技能下文给的目录方案也能帮你把它们集中管理只是同步时注意区分轻技能全量同步、重技能按需同步。2.3 Skills的发现机制决定了文件命名和描述比内容更关键还有一个容易踩坑的深层机制Agent加载Skills时并不是把你目录里所有文件一股脑塞进上下文而是先扫描每个技能文件的名称和描述字段跟当前对话任务做匹配命中了才会加载正文。这意味着即使你的技能正文写得再精彩如果文件名没有特征、描述写得太泛Agent很可能根本看不到它——也就是常说的装上了但没触发。这个机制直接影响了管理方法的设计想要让一套Skills在多个Agent里都容易被触发就得在文件命名和描述字段上花心思而不是只关注正文质量。也正因如此我后面的统一初始化方案里特意把规范命名和优化描述作为第一步这是有底层逻辑支撑的不是形式主义。3. 统一管理方案的整体设计与核心目录结构先直接给出我实际在用的目录结构大家对照着看后面所有的解释都围绕这个结构展开~/agent-skills/ ├── LICENSES/ │ ├── mit.txt │ └── cc-by-sa.txt ├── _templates/ │ ├── skill-frontmatter.md │ └── skill-readme.md ├── code-review/ │ ├── SKILL.md │ ├── rules/ │ │ ├── security.md │ │ └── style.md │ └── scripts/ │ └── quick-lint.py ├── api-design/ │ ├── SKILL.md │ └── examples/ │ └── restful-api.md ├── database-optimization/ │ ├── SKILL.md │ └── scripts/ │ └── slow-query-analysis.py ├── docs/ │ ├── unified-skills-guide.md │ └── migration-checklist.md └── sync/ ├── sync-claude.sh ├── sync-codex.sh ├── sync-opencode.sh └── sync-all.sh这套结构的设计出发点很简单用一个独立的仓库目录~/agent-skills作为所有技能的唯一事实来源然后通过同步脚本把不同技能软链或复制到各个Agent对应读取的目录里。~/agent-skills本身建议用Git管理这样每次改动有历史、可回滚、方便协作。各子目录的作用如下LICENSES/存放你搜集或编写技能时采用的许可证文本。很多人忽略这一步但如果你的技能来源于GitHub上某个开源仓库保留对方的License既是法律要求也能避免后续纠纷。_templates/存放新技能的初始化模板。每次想新增技能时直接复制模板再填内容能保证所有技能都长成统一结构这比每次凭感觉新建文件要稳定得多。每个技能一个目录目录名即技能名内部固定使用SKILL.md作为主文件可选的rules/、examples/、scripts/放辅助资源。这种一名一目录、主文件固定名的结构是为了让同步脚本写起来最简单——不用在同步时做复杂的文件名映射。docs/存放整体的使用文档和迁移检查清单相当于自解释手册方便你一个月之后再看还能立刻上手。sync/存放所有同步脚本这也是整个方案的核心工具链直接决定了日常维护成本。这套结构看起来平平无奇但真正关键的是它解决了一个底层问题把技能散落在各个Agent目录变成了技能统一存储在公共仓库、Agent目录只放入口链接。前者是混乱的根源后者才具备可维护性。4. 三种Agent的Skills目录适配要点写清路径才能真正一处更新全端生效搞清楚统一仓库之后接下来的核心问题就是如何把仓库里的技能正确安装到不同Agent的读取目录中。每个Agent的技能目录路径、文件格式、加载规则各不相同我把自己实配过的三种主流Agent的情况列成一张表方便大家对照Agent技能读取目录默认主文件格式要求附加资源支持加载机制要点Claude Code.claude/skills/[技能名]/SKILL.md含YAML frontmattername, description必填同目录下可放任意辅助文件按文件名和description匹配任务Codex~/.codex/skills/或项目内.codex/skills/SKILL.md支持灵活frontmatter字段支持子目录和脚本同样按技能名和描述检索OpenCode.opencode/command/每个技能一个Markdown文件无强制frontmatter基本只认单文件脚本需内部引用按文件内容整体作为可调用命令提示上表中的路径是基于这几个Agent在近半年的主流稳定版本工具迭代很快具体路径最好以你自己安装版本的实际输出为准。不确定时可以分别查看各Agent的官方文档或者直接在对应目录里放一个测试技能看是否被加载。我自己在用的同步思路直接用最稳妥的软链接方式而不是复制。好处在于仓库里改了技能正文各个Agent目录里的链接指向不变立即就能读到新内容不需要每次改完都重新同步一遍。软链接方案在各平台都支持但要注意macOS和Linux直接用ln -sWindows需要以管理员身份运行终端、用mklink /D创建目录链接细节我会在第5节里展开。下面给出Claude Code的同步脚本示例大家可以直接保存为sync-claude.sh#!/usr/bin/env bash # sync-claude.sh # 将 ~/agent-skills 下的技能软链到 .claude/skills 目录 set -euo pipefail SOURCE_ROOT$HOME/agent-skills TARGET_ROOT.claude/skills mkdir -p $TARGET_ROOT # 遍历源码根目录下所有含 SKILL.md 的子目录 for skill_dir in $SOURCE_ROOT/*/; do skill_name$(basename $skill_dir) if [ -f $skill_dir/SKILL.md ]; then # 如果目标链接已存在先删除旧链接避免冲突 rm -rf $TARGET_ROOT/$skill_name ln -s $SOURCE_ROOT/$skill_name $TARGET_ROOT/$skill_name echo linked: $skill_name else echo skip (no SKILL.md): $skill_name fi done这个脚本做了几件正确的事情用了set -euo pipefail防止静默错误删除旧链接再重建避免同名残留只链接含SKILL.md的目录避免把_templates、LICENSES这类辅助目录误链过去。你可能会问为什么不做增量判断、每次全量重建实测下来技能数量在30个以内时全量重建耗时基本可忽略而全量重建逻辑简单、不容易出BUG性价比最高。Codex和OpenCode的脚本逻辑完全一致只需要把TARGET_ROOT替换成对应路径。如果你用的是其他Agent只要找到它读取技能的真实目录套同一个脚本模板就能行。5. 新技能从0到1初始化清单、frontmatter规范和命名策略5.1 为什么必须先有初始化清单再谈管理管理多个技能的时候真正拉低效率的往往不是技能运行时的性能而是技能创建时的随意性。今天新建技能时用中文名明天又用英文缩写命名今天写描述写了三行明天只写了一个词。当时感觉没什么等到技能数量上来、要靠Agent自动匹配的时候问题就爆发了——一多半技能因为命名混乱、描述缺失而无法被触发只能手动点名调用这等于把技能降级成了普通文档。所以有了统一目录之后紧接着要做的就是定义一套新技能入场规范。我把它做成了初始化清单每次新建技能都对照执行复制_templates/skill-frontmatter.md确认frontmatter无缺漏。name字段必须是动词短语 对象的英文格式例如review-nodejs-code、generate-openapi-spec不要用技能1这类无意义命名。description字段写三行左右一句话说明这个技能做什么一句话说明典型触发场景一句话说明它不做什么。主文件固定命名为SKILL.md。正文结构统一为场景描述 - 输入要求 - 执行步骤 - 输出格式 - 注意事项。如果技能需要脚本脚本放scripts/子目录脚本内部一律使用相对路径引用资源。更新skill-readme.md记录版本号和变更历史。这套清单看起来繁琐却是我整个管理方案里最值钱的部分。因为一旦所有技能都按同一套结构生成后面的同步脚本、多端复用、团队协作全都顺了——模板和规范才是简单方法的底座。5.2 frontmatter里最容易翻车的三个字段我给大量开源Skill包做过兼容性适配发现frontmatter里最容易翻车的就是name、description和allowed-tools这三个字段。name字段容易翻车在大小写和分隔符上。有些Agent内部做技能名匹配时对大小写敏感ReviewCode和review-code会被当成两个技能一旦代码里同时对两个名字做了引用就会产生歧义。实践中建议统一用小写加连字符规避一切大小写问题。description字段则容易写得太像广告词或者太空泛。比如这是一个很厉害的代码审查技能这种描述等于没写。Agent做任务匹配时靠的是语义相似度描述里应该包含触发场景的关键词。举例来说可以这样写Review Node.js code for common security vulnerabilities, focusing on input validation, authentication logic, and dependency risks. Use when user asks for code review or security check in a Node.js project. Does not refactor code.allowed-tools字段则要留意版本差异。部分Agent支持通过该字段限制技能内部可以调用哪些工具但不同框架对这个字段的支持度不一致有的直接忽略、有的严格校验。为了复用性我建议主文件里不要声明这个字段如果确有限制需要放到Agent专属的扩展配置里而不是写进公共的SKILL.md。5.3 命名策略直接决定Agent找不找得到技能除了frontmatter里的name同步到Agent目录后的可读性命名也很关键。Claude Code这类工具在技能匹配时会把技能目录名、文件名、描述一起纳入检索所以目录名的语义同样重要。我建议采用[领域]-[动作]-[对象]三段式命名例如database-slow-query-analysis、frontend-react-accessibility-audit。这样的命名有双重好处对Agent来说语义足够清晰容易在对话中被匹配到对人来说在文件管理器和Git提交记录里也能一眼定位。6. 多端同步的实操细节与踩坑记录从脚本编写到维护节奏6.1 软链接在三大平台的不同操作跨平台同步是这个方案里最容易被低估的环节。很多人以为复制一套脚本就完了结果换台Windows电脑就傻眼。我实际踩过的坑主要有三个第一个是Windows的软链接需要管理员权限。普通用户运行ln -s会直接报错必须右键以管理员身份运行终端或者给当前用户开启开发者模式。否则就算脚本执行成功也会生成一个无效的目录占位符。第二个是文件路径分隔符问题。如果同步脚本里硬编码了/在Windows上虽然大多数现代终端能自动转换但一旦脚本里有拼接字符串的操作就很容易出问题。最稳妥的做法是在脚本头部统一用变量定义路径不要到处写斜杠。第三个是macOS的ln -s参数顺序问题。很多人会把源和目标写反导致生成一个指向不存在的死链接。正确写法是ln -s 实际存在的源路径 想要创建的链接路径。如果你主要用的是有图形界面的Windows环境那我更建议在PowerShell里执行下面这种等价操作# 以管理员身份运行 PowerShell New-Item -ItemType Directory -Force -Path $env:USERPROFILE\.claude\skills Get-ChildItem -Path $env:USERPROFILE\agent-skills -Directory | ForEach-Object { if (Test-Path $($_.FullName)\SKILL.md) { $target $env:USERPROFILE\.claude\skills\$($_.Name) if (Test-Path $target) { Remove-Item $target -Force } New-Item -ItemType SymbolicLink -Path $target -Target $_.FullName } }6.2 同步节奏不要每次改完都跑全量用小时级批量处理这里分享一个实践心得。最开始我每次改完任意一个技能就立刻跑一遍全量同步脚本结果一天下来跑了几十次大部分时间都在处理毫无变化的目录。后来我把节奏调整为集中改动时每次收尾跑一次全量同步日常小改攒到某个时间点统一跑。这样做的收益是每轮同步结束后我可以集中验证一批技能的加载效果而不是被随时可能跳出来的小问题打断思路。还有一个容易被忽略的点Codex和Claude Code在较长对话中会缓存技能加载结果。如果你改了技能正文但Agent一直表现旧行为先别急着怀疑同步出问题重启一下对话会话往往就能解决。6.3 为什么我用软链接而不是复制版本一致性和免重复同步有读者可能会问直接用Git clone 复制不也能实现一样的效果吗为什么非要用软链接。这里有个底层区别如果采用每次同步都复制文件的方式仓库改了内容之后各个Agent目录里的副本不会自动跟上必须记得再跑一次复制操作。一旦忘记同步就会出现某些Agent用的是新技能、某些还在用旧技能的割裂状态。而软链接因为只是入口改动实时可见天然规避了副本不同步的问题。当然软链接也有代价如果某个Agent在做版本升级时强制重装技能目录可能需要重建链接另外如果你把工作项目目录打包发给别人软链接指向的本地路径在对方机器上不存在会导致技能缺失。如果是团队协作场景、或者经常需要把项目整体移交那更建议改成复制到Agent目录的策略牺牲一点实时性换取可移植性。关键是这两种方式都要心里有数别混着用。7. 团队协作与技能迭代用Git分支管理一套技能仓库管理多个Agent的技能绝大多数情况下是个人行为但如果你的团队里每个人都维护自己的Agent技能这时候一套统一管理方案就要升级成一套统一的协作流程。我的建议是把~/agent-skills这个仓库变成团队共享的Git仓库每个成员clone到本地然后在自己的机器上跑同步脚本。具体的协作细节如下。主干分支保留稳定版本每个技能目录都需要有明确的功能说明和适用版本记录。新增技能时先开一个分支技能达到自己觉得能用了再合入主干。每个技能目录下的skill-readme.md必须记录当前技能适配哪些Agent、哪些版本需要额外配置减少别人拿来就能用吗这种反复确认的成本。如果有人对同一个技能做了不兼容的修改尽量在PR描述里写明影响范围避免合入后其他人本地同步出问题。建议每周做一次技能清单review核对仓库里的技能和实际正在用的技能把废弃的删掉避免仓库像杂物间一样越堆越多。这里多提一句技能的生命周期我最初囤了几十个技能很多是在某个项目里一次性用完之后就再没碰过。真正高价值的技能集合应该是少量、精准、可复用而不是多而杂。定期清理淘汰技能其实和升级技能同等重要。以Claude Code为例如果你想给某个技能加上只有自己机器能用的额外工具权限可以在技能目录里单独放一个claude.settings.json扩展配置而不要把这个配置写进公共目录否则同步到其他同事机器上可能触发未授权工具的报错。这个细节能避免团队里最常见的为啥我这边加载失败问题。8. 实际使用中的坑与排查思路加载失败、匹配不佳、死链接即便方案再简单实际操作中还是会有各种意外。我把过去两个月里遇到最多的问题按频率从高到低列出来每条都附上排查链路方便大家直接对照。8.1 技能加载失败但同步脚本没有报错这个问题的隐蔽性在于脚本输出显示linked: xxx但实际测试时Agent就是找不到技能。我的排查顺序是先确认Agent当前项目的工作目录。Claude Code在项目根目录启动时会读取项目下的.claude/skills但如果你在子目录里启动Agent它可能根本看不到根目录下的技能。这个问题特别容易出现在打开某个子文件夹使用AI工具的场景。检查软链接是否有效。在终端执行ls -l .claude/skills看输出里链接目标是否有-指向以及指向路径是否存在。如果显示红色、内容里有No such file说明源路径出了问题。查看Agent日志或调试模式输出。Claude Code可以用/status命令查看加载状态OpenCode有--verbose参数Codex则可以在启动时加-v输出详细日志。如果以上都正常大概率是缓存问题重启对话会话即可。8.2 技能能被加载但Agent从不主动调用它这是匹配不佳类问题。通常的原因不是格式问题而是描述和实际场景不匹配。我处理这类问题有一个很有效的办法把实际使用的场景语句原样抄进description里。比如你日常说的是帮我把这个接口改成RESTful风格那就把rephrase to RESTful style这类关键词写进描述这样Agent在语义匹配时命中率会明显提升。8.3 重装了Agent之后所有技能链接失效这是软链接方案的一个固有特点。如果你扩容磁盘、迁移了用户目录或者把Agent整个卸载重装之后发现技能目录空掉了一般都是因为链接指向的旧路径不存在了。解决办法是把~/agent-skills迁移到新位置后重新执行一遍同步脚本。所以建议把同步脚本放在sync/目录里也是这个原因——每次迁移后重跑一次一分钟就能恢复。8.4 同一个技能在两个Agent里的表现不一致这个问题通常不是因为技能文件本身而是因为不同Agent对同一份Markdown的解析程度不一样。比如Claude Code对frontmatter里的某些扩展字段有专门解读会触发额外行为而Codex可能把同样的字段当普通文本不产生任何动作。遇到表现不一致优先检查这个技能是否依赖了某个Agent的特定字段。如果有把这些特定字段单独抽出来放Agent专属配置公共SKILL.md只保留三种Agent都支持的基本字段。9. 下一步可以怎么扩展从个人维护到半自动技能库按照上面这套方法你已经能做到一套技能仓库、统一管理、多端同步。如果你想继续往下走有几个成本不高的扩展方向我按推荐顺序列一下。第一个方向是给同步脚本加上按需同步参数。比如在sync-all.sh里增加--only code-review选项临时改动单个技能时就不用跑全量。实现很简单本质上就是脚本多接收一个可选的技能名参数。第二个方向是给技能正文增加版本标记。我建议在每个SKILL.md里加一个version: 1.2.0字段这样当Agent出现异常行为时能通过查看技能版本快速定位是不是最近改动导致的。虽然不是必须但长期维护多个技能时很实用。第三个方向是如果你愿意折腾可以做一个简单的技能索引页——把每个技能的名称、用途、适用Agent、最近更新时间列在一个Markdown文件里放在仓库顶部。这个索引既能用来快速查阅也可以在未来接入自动化文档生成工具。至于是否要做一个自动化的技能管理App我的看法是在自动化和可维护性之间需要平衡。脚本方案已经能覆盖90%的需求引入新框架反而会带来学习和维护成本。当前阶段一个Git仓库加三个同步脚本已经能解决绝大多数人的痛点。10. 写在最后一点个人体会经过这两个月的整理和实际使用我最大的体会是管理多个Agent的Skills难点从来不在技术上——它不需要你懂多深的人工智能原理也不需要你掌握多复杂的工具链。真正的难点在于约束自己愿意花一晚上把散落的技能归拢到一个仓库愿意遵循一套看似有点啰嗦的命名和模板规范愿意在每次新增技能时多花两分钟写清楚描述。但一旦把这些基础打牢后续的收益是倍数级的新Agent出来时你不再担心技能迁移问题接到新项目时你不再花半小时翻找可复用的技能更关键的是你开始拥有属于自己的一套方法论而不是永远在追着工具跑。如果你也正被多Agent、多Skills的问题困扰不妨从今晚开始先把所有技能文件列个清单看看它们到底分布在多少个目录里然后照着这篇文章的结构把它们归拢起来。相信我这个整理过程本身就很有价值。
