
1. 项目定位superpowers 到底是个什么东西1.1 一句话定义先说人话superpowers是一个专门给 AI 编程助手尤其是 Codex CLI 这类终端工具用的技能扩展包。它不是编程语言不是框架也不是另一套 IDE而是一套“把提示词、脚本和标准操作流程打包成可复用技能”的方案。当你给 Codex 加上 superpowers 之后原本“问一句、答一句、全靠随机应变”的 AI 助手会变成一个“接到任务就知道先做什么、后做什么、调用什么工具”的稳定输出者。我第一次接触这个项目的时候第一反应是“这不就是一堆 markdown 模板再加几个 shell 脚本吗”。但真正用了一段时间后我改变了自己的判断。模板和脚本只是表象superpowers 真正的价值在于思路它把人类专家完成某类任务的隐性经验显性化成了 AI 能按步骤执行的技能仓库。举个例子你让 AI“帮我看一下这段代码有没有问题”和让它“先用编译器和静态检查工具收集问题清单再按严重程度逐项分析最后给出修复建议”是完全两种体验。前者是抛硬币后者是流水线。我这篇文章想聊透三件事第一superpowers 为什么值得装第二它在工程上是怎么设计的技能到底怎么组织第三我实际动手做的一个 Java 技能案例以及我在踩坑之后总结出来的一套排查方法。跟 Codex 打过交道的朋友应该都知道默认状态的 AI 编程助手确实强但它的强是“知识面广”而不是“操作稳”。superpowers 正好补上了后者。1.2 它到底解决了什么问题如果你琢磨过“为什么我用 Codex 总觉得像在带新人”这个问题你就已经摸到 superpowers 的核心了。默认情况下AI 编程助手执行任务靠的是模型当时的“临场发挥”。你把需求描述得越清晰上下文给得越完整它的输出就越好。但问题在于“描述得清晰”本身是个挺高的要求。你让 AI “重构这个模块”它可能上来就改代码完全不先跑测试、不梳理依赖关系、不确认重构边界最后给你一坨没法合并的改动。superpowers 的核心假设是把不可控的“临场发挥”变成可控的“标准动作”。它通过一套技能描述文件告诉 AI 在特定场景下应该执行哪几步、用什么工具、产出什么格式。比如一个“代码审查技能”它的描述文件里会写明第一步列出本次变更涉及的文件第二步对每个文件运行 lint 和类型检查记录错误第三步按“正确性、可读性、性能、安全性”四个维度分别给出问题列表第四步为每个问题标注严重级别并给出最小修复建议。AI 读到这样的技能描述后不会自作主张乱来而是照着这个流程一步步走。这就像你不是让实习生“随便看看这份合同”而是告诉他“先核对金额、再核对日期、最后检查违约责任条款”效果自然不同。我个人的理解是superpowers 的本质就是把“提示词工程”标准化、工程化了。以前大家写提示词都是在对话窗口里临时组织语言superpowers 则把这些提示词固化到文件里配上可执行的辅助脚本让 AI 在合适的时机自动加载。它不改变模型本身的能力但它极大提高了模型能力的“兑现率”。1.3 这套方案适合谁不是所有人都有必要上 superpowers。如果你只是偶尔用 Codex 解释一段报错、写个一次性脚本那额外配置一套技能系统完全是负担。但如果你是下面这几种情况我会比较推荐团队里的 AI 重度用户。你每天都在用 AI 写代码、改 bug、做 review并且你发现同样的任务每次输出质量飘忽不定。你需要的是“稳定”技能化正好解决这个问题。负责维护多个项目的开发者。项目之间技术栈不同、规范不同、测试习惯不同。superpowers 允许你按项目维护不同的技能目录比如 Java 项目用一套“先编译再写单测”的技能前端项目用另一套“先跑 lint 再改样式”的技能。希望把个人经验沉淀成团队资产的技术负责人。你自己知道“这个项目的测试应该怎么写”“那个模块重构时要注意什么”但你不可能每次都给 AI 重复讲一遍。技能文件写一次团队所有人都能复用新人也能通过读技能文件快速理解老项目的工程规范。对于纯新手我建议你先别急着搞一堆花哨技能。先把 Codex 基础用法跑顺再装 superpowers从两三个高频技能用起比如“单测生成”“报错分析”“代码审查”。等你自己真正理解技能文件是怎么生效的再往深了折腾。2. 快速安装与环境准备2.1 前置依赖工欲善其事必先利其器。我建议按下面的清单准备环境版本号是我实测过的比较稳的组合依赖推荐版本说明Node.js18 或 20 LTSCLI 工具链的运行时依赖Codex CLI0.9 及以上目前 superpowers 主要增强对象Git2.30 以上拉取技能仓库和做版本管理jq1.6 以上很多辅助脚本会用 jq 解析 JSON 输出如果你平时用 Windows建议优先装好 WSL 或者 Git Bash因为技能系统里的辅助脚本大量使用了 shell 语法纯 CMD 环境会非常痛苦。我在这上面浪费过不少时间后面排查章节会单独提。2.2 安装步骤我用的是最常规的安装方式把 superpowers 仓库 clone 到本地然后通过 Codex CLI 的配置项把它挂载进去。具体操作我直接给命令都是我在终端里跑过的# 1. 克隆仓库到本地固定目录建议不要放项目内避免 git 嵌套 git clone https://github.com/example/superpowers.git ~/.superpowers # 2. 进入目录安装依赖没有安装脚本就直接跳过一次 cd ~/.superpowers npm install 2/dev/null || true # 3. 在 Codex 的配置目录里创建一个入口配置 mkdir -p ~/.codex cp ~/.superpowers/superpowers.json.example ~/.codex/superpowers.json # 4. 编辑 Codex 的全局配置加载你刚生成的 json codex config set superpowers ~/.codex/superpowers.json如果上面命令里的codex config set在你的版本里不存在也不用着急。你会需要手动打开 Codex 的配置文件一般位于~/.codex/config.toml把类似下面这一段追加进去[superpowers] enabled true skills_path ~/.superpowers/skills这里有个小细节我要强调skills_path是指向技能集合目录的不是指向单个技能目录。superpowers 会在这个目录下扫描所有子目录每个子目录如果含SKILL.md文件就会被识别成一个可用技能。2.3 验证安装是否生效装没装好最怕的就是“自我感觉装了实际根本没生效”。我建议用下面这个从浅到深的验证顺序第一步确认技能仓库能被扫描到ls ~/.superpowers/skills/如果里面有plan、debug、test之类的基础技能目录说明仓库没问题。第二步在 Codex 对话里直接触发一个内置技能比如请使用 plan 技能帮我规划一下“给后端服务增加接口限流”的实施步骤。如果 superpowers 生效Codex 会先加载plan技能里的步骤说明然后按步骤输出计划而不是直接凭空给你列几点建议。你很容易从输出的格式看出区别技能化的输出会带“第 1 步、第 2 步、第 3 步”这样的结构化推进而不是踌躇半天后给你一段散文。第三步检查日志确认技能文件被加载。Codex CLI 在 verbose 模式下会打印实际读取了哪个 SKILL.md。如果日志里出现了loaded skill plan from ~/.superpowers/skills/plan/SKILL.md那就是真的挂上了。3. 核心机制技能是怎么跑起来的3.1 技能的文件结构在动手写自己的技能之前你得先理解 superpowers 对一个技能目录的约定。一个标准技能目录的骨架长这样skills/my-skill/ ├── SKILL.md ├── scripts/ │ ├── run_check.sh │ └── format_report.py └── references/ └── coding_standards.md三个部分各司其职。SKILL.md是给 AI 读的说明书告诉它“我是干什么的、什么情况下使用、执行步骤是什么、附带的脚本怎么调用”。scripts/是给 shell 或编程语言用的可执行辅助脚本用来完成 AI 模型不方便直接完成的操作比如精确统计代码行数、批量替换文件、解析 JSON 报告。references/是参考资料AI 在执行技能时可以按需阅读比如团队编码规范、历史决策记录、领域背景知识。我一开始犯过的错误是把所有内容全塞进 SKILL.md脚本和参考资料一概不分家。结果就是技能文件越来越长AI 读取时经常漏掉关键步骤。后来我接受的教训是SKILL.md 只写“什么时候用、按什么顺序做、产出什么”细节和脚本都放在外部文件里让 AI 按需取用。这跟写代码是一个道理高内聚低耦合。3.2 SKILL.md 的格式规范SKILL.md 不是普通的 Markdown 文档它带有一个严格的 frontmatter 头以及一套约定俗成的正文结构。最简可用的格式如下--- name: generate_unit_tests description: 当用户要求为 Java/Kotlin/Scala 等 JVM 项目生成单元测试时使用。自动识别测试框架、分析被测类、生成可编译的测试代码。 triggers: - 生成单测 - 补测试 - 写单元测试 - unit test version: 1.0.0 steps: - 识别项目构建工具Maven/Gradle和已有测试框架JUnit 4/5/TestNG - 运行一次编译命令收集当前编译错误 - 扫描被测类的公开方法列出需要覆盖的边界条件 - 在对应 src/test 目录下生成测试代码确保编译通过 - 运行新增测试反馈失败项并迭代修复 scripts: detect_build_tool: scripts/detect_build_tool.sh run_tests: scripts/run_tests.sh --- # 生成单元测试 ## 使用场景 当用户要求为 JVM 项目补充单元测试时按照步骤执行... ## 详细步骤 ### 1. 识别构建工具与测试框架 执行 detect_build_tool 脚本根据输出判断项目类型... ## 注意事项 - 不要修改被测类的业务逻辑 - 生成的测试必须能被当前测试框架直接执行 - 如果被测类依赖外部服务优先使用 Mockito 等框架隔离这里的顺序很讲究。frontmatter 里的description是 AI 决定“要不要使用这个技能”的关键它写得越具体命中率越高。triggers是触发词清单你可以在里面放用户常见说法。steps是执行流程的浓缩版AI 会把它当成任务清单逐项完成。正文里的详细步骤则可以写得更细包含具体命令、命令解释和预期输出。有一个最常见的坑AI 在对话中可能不会主动去读 SKILL.md 里的全部正文。它往往只根据description判断是否调用技能然后再根据steps列表展开执行。所以真正决定技能命运的是 frontmatter 里的 description 和 steps 字段正文是辅助。我在 5.1 节会详细讲这个问题的排查方法。3.3 参数的传入与结果回收技能不是闭门造车它需要接收用户请求里的具体信息。比如“给 OrderService 补单测”和“给 UserController 补单测”路径不一样、方式不一样技能必须能拿到这个参数。在 superpowers 的机制里参数传递主要通过两个途径。第一是 Codex 的自然语言上下文AI 在加载技能后会把当前对话中的实物参数比如目标类名、文件路径、构建工具提取出来作为执行步骤的具体输入。第二是脚本调用时的参数传递SKILL.md 描述的步骤里可以写明“执行run_tests.sh参数为 class_name”此时脚本接收的第一个参数就是这个类名。在这里我强烈建议你在 SKILL.md 里对参数做显式声明。比如## 参数说明 - target_class用户指定的被测类完整类名如 com.example.OrderService - target_file被测类的源文件路径可由 AI 在加载技能时自动推断为什么必须显式声明因为模型在技能加载后有时候会“忘记”去提取用户需求里的目标对象。如果你在 SKILL.md 里写明“第一步必须提取 target_class 参数如果用户没有提供则询问用户”它就能稳定地执行参数提取动作而不是默认用当前打开的第一个文件。这算是我踩过最多次坑的地方之一。脚本产生的输出也不该浪费。AI 在执行技能步骤时会读取脚本的标准输出来判断下一步行动。所以你的脚本要尽量输出结构化的、可直接被 AI 理解的内容。举个例子detect_build_tool.sh的输出建议是BUILD_TOOLmaven TEST_FRAMEWORKjunit5 SRC_DIRsrc/main/java TEST_DIRsrc/test/java这种 keyvalue 的输出格式AI 一眼就能读懂也方便它后续引用。相比口语化的“看着像 Maven 项目”结构化输出让 AI 的后续判断稳定得多。4. 实操案例给 Java 项目写一个单测生成技能4.1 场景设定光讲机制有点干我带你看一个我实际做过的技能。假设团队里有一个 Java 8 Maven 的老项目测试覆盖率偏低核心服务类OrderService几乎没有单测覆盖。每次提“帮 OrderService 补单测”AI 输出的测试代码要么编译不过要么没构造好依赖对象总之就是“能用但很累”。我决定写一个专门的java_unit_test技能让 AI 严格按我团队的习惯来。我先定好了需求目标技能要能自动识别 Maven 项目结构、检测 JUnit 版本、分析 OrderService 的公开方法、生成带 Mock 依赖的测试类并在生成后自动跑一次测试。这几个能力拆开都不难难的是把它们串成一条 AI 能稳定执行的流程。4.2 创建技能目录与说明文件我按 superpowers 的规范创建了技能目录~/.superpowers/skills/java_unit_test/。下面是这个技能的核心文件SKILL.md--- name: java_unit_test description: 用户要求为 JVM 项目Java/Kotlin/Scala生成或补充单元测试时使用尤其是 Maven 管理的项目。优先识别构建工具、测试框架和被测类生成可编译、可运行的测试代码。 triggers: - 生成单测 - 补测试 - 写单元测试 - 增加测试覆盖 - unit test version: 1.0.0 steps: - 使用 detect_build_tool.sh 确认项目构建工具和测试框架 - 执行 mvn test-compile 收集当前编译状态 - 扫描被测类公开方法列出需要覆盖的方法签名 - 在 src/test/java 下生成与主代码同包名的测试类 - 使用 mvn -Dtest生成的测试类 test 运行测试并反馈失败原因 scripts: detect_build_tool: scripts/detect_build_tool.sh run_single_test: scripts/run_single_test.sh --- # Java 单元测试生成技能 ## 使用场景 当用户要求生成单测、补测试或提高覆盖率时本技能负责规范流程。 ## 详细步骤 ### 1. 确认构建工具与框架 执行 detect_build_tool 脚本读取 BUILD_TOOL、TEST_FRAMEWORK、TEST_DIR 三个关键输出。 ### 2. 编译检查 执行 mvn test-compile -q。如果编译失败先输出失败原因不要继续生成测试代码。 ### 3. 方法扫描 读取被测类源码提取所有 public 方法。对每个方法记录方法名、入参类型、返回类型、是否 static。 ### 4. 生成测试代码 - 测试类放在 src/test/java 下包名与主代码一致类名以 Test 结尾。 - 构造函数入参较多时优先使用 Mockito 的 Mock 和 InjectMocks。 - 对外部依赖返回值的 Mock 行为必须在测试方法内显式 given-when-then。 ### 5. 运行测试 执行 run_single_test 脚本脚本接受测试类名作为参数。以 JUnit 5 为例命令是 bash mvn -DtestOrderServiceTest test -q参数说明target_class必需参数用户指定的被测类全限定名。如果用户没有提供扫描 src/main/java 下最可能的主类并询问确认。target_package可选参数被测类所属包名用于确定测试类摆放路径。注意事项不得修改被测类源码。测试必须使用项目现有的测试框架不得引入未经确认的新依赖。如果测试依赖外部服务优先 Mock不连接真实环境。这份 SKILL.md 我给团队其他人看过他们的反馈是“看起来不复杂但 AI 执行结果确实稳了很多。”原因是它强制 AI 在生成代码之前先跑 mvn test-compile这一步把大量“因上下文缺失导致的瞎写”提前拦住了。 ### 4.3 编写辅助脚本 光有 SKILL.md 还不够前面提到的两个脚本也得备好。检测脚本的核心逻辑是这样 bash #!/usr/bin/env bash # scripts/detect_build_tool.sh set -e if [ -f pom.xml ]; then echo BUILD_TOOLmaven echo TEST_DIRsrc/test/java elif [ -f build.gradle ] || [ -f settings.gradle ]; then echo BUILD_TOOLgradle echo TEST_DIRsrc/test/java else echo BUILD_TOOLunknown echo TEST_DIRsrc/test fi if grep -q junit.jupiter pom.xml 2/dev/null; then echo TEST_FRAMEWORKjunit5 elif grep -q junit:junit pom.xml 2/dev/null; then echo TEST_FRAMEWORKjunit4 else echo TEST_FRAMEWORKunknown fi这个脚本很短但它做了关键的事把“AI 猜项目结构”这个问题变成了“脚本探测项目结构”。猜就会错探测就不会错。第二个脚本负责跑单个测试类#!/usr/bin/env bash # scripts/run_single_test.sh # 用法: ./run_single_test.sh 测试类名 set -e TEST_CLASS$1 if [ -f pom.xml ]; then mvn -Dtest${TEST_CLASS} test -q elif [ -d src ] [ -f gradlew ]; then ./gradlew test --tests ${TEST_CLASS} else echo ERROR: 未识别的构建工具 2 exit 1 fi一个细节是set -e脚本遇到第一个错误就退出避免 AI 拿到一个被截断的错误输出后继续硬写。在 superpowers 的实践中“让失败快速暴露”比“尽力跑完”重要得多。4.4 实际触发效果技能写好之后我在 Codex 里输入了这么一句话用 java_unit_test 技能给 OrderService 补单测重点覆盖订单状态流转的边界情况。Codex 会根据triggers里的关键词匹配到技能然后按 SKILL.md 的步骤执行。我在现场观察到的流程大致是AI 先执行detect_build_tool.sh输出BUILD_TOOLmaven和TEST_FRAMEWORKjunit5确认这是 Maven JUnit 5 项目AI 执行mvn test-compile -q看到编译通过继续下一步AI 读取OrderService.java源码提取出createOrder、cancelOrder、payOrder等 public 方法AI 在src/test/java下生成了OrderServiceTest.java对依赖的OrderRepository用 Mockito 做了 mockAI 执行run_single_test.sh OrderServiceTest第一次有 2 个用例失败失败原因是 mock 的save方法没有匹配参数AI 自动修正后重跑测试通过。整个过程真正做到了“自动纠错”但纠错的前提是流程里每一步都有明确产出和明确判断标准。如果没有技能约束AI 很可能会在生成测试代码后直接“赢了就跑”完全不跑测试或者失败了也不回头修。这个技能把“必须跑到绿”写进了步骤效果立竿见影。到这里你应该也能感觉到superpowers 的实用价值不在于它的代码多复杂而在于它给 AI 的“行动约束”和“反馈循环”。约束保证方向反馈保证收敛。5. 常用问题与避坑清单5.1 技能识别不到AI 根本不加载这是被问得最多的一个问题。你辛辛苦苦写了技能结果问 AI 它却说“我没有找到这个技能”。大多数情况下问题出在SKILL.md的 frontmatter 上。我总结过几个高频原因description写得过于模糊。比如只写“生成单元测试”AI 在收到“帮我补测试”这类说法时无法把用户意图和技能描述对上。解决方法是把描述写得像“条件表达式”什么场景、什么项目类型、什么任务全部写清楚。triggers里的关键词和用户的实际表达对不上。用户说“补测试”你只写“写单测”匹配率就低。建议你在团队里收集几种真实说法全部放进 triggers。文件名不对。必须是SKILL.md大小写都不能错写成skill.md或者Skill.md都不行。目录层级也必须是skills/xxx/SKILL.md不能多套一层。技能目录里有语法错误。frontmatter 是 YAML 格式如果name字段里用了空格、冒号等特殊字符解析器会直接失败整个目录被跳过。建议写完 SKILL.md 后用 YAML 校验工具过一遍。排查时最快的方式是打开 Codex 的 verbose 日志搜索技能目录扫描记录看看你的技能有没有被加载。如果没有被加载日志里通常会有解析错误的提示。5.2 参数传不进去脚本收到空值明明用户说了“给 OrderService 补单测”脚本却收到空参数或者 AI 自己脑补了一个不存在的类名。这种问题我遇到太多次了。核心原因是 SKILL.md 没有显式声明“必需参数”。AI 不是不聪明而是它不知道“必须要把用户提到的类名提取出来”这个动作如此重要。解决办法就是我在 3.3 节强调的在 SKILL.md 里加一个## 参数说明区块明确写清楚哪个参数是必需的、怎么提取、提取不到时应该怎么办。把参数提取动作写进步骤的第一条比写十句提醒都管用。另外如果用户输入里没有包含目标类名我建议不要生成默认值而是直接让 AI 回复“请提供被测类名”这样反而避免后面一连串的错误。另一个容易踩的坑是路径歧义。脚本默认在技能目录下执行不是当前项目目录。你在 SKILL.md 里让 AI 调用scripts/detect_build_tool.sh这个相对路径依赖当前工作目录。稳妥做法是在脚本调用前显式cd到项目根目录或者从上下文里的workspace字段读取项目路径再把绝对路径传给脚本。5.3 Java 技能准确率低问题出在哪如果你发现同样的技能在 Java 项目上表现远不如在 Python 项目上别急着怪模型。Java 是个“强类型、重样板”的语言AI 生成代码时最容易犯两类错一是构造对象时漏掉必填参数二是 mock 的静态方法或 final 方法没生效。这两类问题单靠提示词很难根治但可以通过技能设计来改善。我的做法是在 SKILL.md 里强加两条规则第一条“生成测试前必须执行编译命令编译不通过不写新代码”第二条“所有依赖对象的 mock 必须使用构造函数注入不使用 Mock 直接注入到 private 字段”。这两条规则把最常见的错误提前预防了。编译规则保证 AI 不会在一个坏基础上继续盖楼constructor 注入规则绕开了 Mockito 对 final 类和 static 方法的不友好限制。另外Java 项目里不同测试框架的写法差异很大。JUnit 4 用BeforeJUnit 5 用BeforeEachMockito 的when在 JUnit 5 里需要ExtendWith(MockitoExtension.class)。所以技能必须先探测框架版本再决定生成风格。我写的detect_build_tool.sh里用 grep 检查pom.xml里有没有junit.jupiter就是为了这一步。检测不到位后面所有代码风格都是错的而且错得很难看出来。5.4 和 WorBuddy 这类工具的关系在社区里不少人会把 superpowers 和 WorBuddy 之类的 agent 管理工具混在一起聊。我个人的理解是两者定位不同但可以配合。WorBuddy 这类工具偏重“智能体的生命周期管理”和“多步骤任务的自动化编排”而 superpowers 更偏重“技能定义和提示词流程的固化”。你可以把 WorBuddy 看成“调度中心”把 superpowers 看成“技能库”它们不是非此即彼的关系。如果在团队里同时用了两者我建议界限要清晰把“什么时候应该用哪个技能”这种判断逻辑放在 WorBuddy 的规则引擎里把“具体步骤和脚本实现”放在 superpowers 的技能目录里。这样调度层和执行层分离后面任何一层改动都不会互相污染。我见过一些团队为了图省事把所有逻辑都堆在调度层最后技能系统变成一个大杂烩改一处崩一片维护成本极高。6. 最后记几条实在体会技能系统跟写业务代码不一样它属于“越迭代越好用”的东西。我一开始只写了两个技能现在身边项目里维护着十几个几乎覆盖了日常高频操作。回头看看最值得分享的体会就三条。第一条不要想着一次写一个大而全的技能。技能粒度越小越稳。比如把“生成单测”和“修复编译错误”拆成两个独立技能比塞在同一个技能里好得多。大技能虽然有面面俱到的满足感但实际用起来很容易在某一步突然失控排查成本反而更高。第二条技能文件一定要进版本库。superpowers 的技能本质上是团队工程规范的一种载体它跟项目代码、架构文档是同等级的资产。技能迭代记录、改动原因、效果回退都应该能通过 git 查得到。我们团队现在要求所有技能变更必须带着 issue 编号提交谁改了哪个技能、为什么改全都可追溯。第三条把一切优化建立在真实验证之上。别只在“看起来能用”就收工。每个技能写完都要找三个真实的、有点难度的任务做压测如果三个任务中有一个表现不佳就回到 SKILL.md 调整步骤或增加注意项。我自己经历过不少“写的时候信心满满用的时候一塌糊涂”的技能最后都是靠真实案例喂出来的。就这些。superpowers 不是什么神兵利器它只是一个把 AI 从“聪明但飘忽”变成“专业且可靠”的辅助方案。能帮你把每天重复的 AI 交互标准化、可复用这本身就是一件值得做的事情。