SDD基于规范编程实战:OpenSpec与SuperPowers的Skill协作指南 1. 从一次“规范漂移”事故说起SDD 到底解决什么问题团队协作里最让人头疼的不是写不出代码而是同一份需求三个人写出三套实现。上周我帮一个做智能硬件的朋友排查问题他们的固件配置模块在两周内被改了四次每次改完测试都过但一上产线就出兼容问题。翻 git log 才发现A 同学按“配置项必须显式声明”写B 同学按“缺省即继承”写C 同学干脆把校验逻辑塞进了初始化函数。三个人都没错错在没有一份机器可读、可被 AI 消费的规范。这就是 SDDSpec-Driven Development规范驱动开发要解决的核心矛盾把“口头约定”变成“可执行契约”。传统开发里规范是写在 Confluence 里的文档人和 AI 都懒得看SDD 里规范是 OpenSpec 定义的结构化文件技能是 SuperPowers 注册的 SKILL.md两者通过文件系统耦合AI 每次动手前先读规范读完再调技能。OpenSpec 负责“写什么”它用 YAML/JSON 描述接口、数据模型、约束条件SuperPowers 负责“怎么做”它把可复用的操作封装成 Skill每个 Skill 一个 SKILL.md声明触发条件、输入输出、依赖资源。两者结合后你给 AI 一句“给配置模块加个版本号字段”它会先查 OpenSpec 里的 schema 定义再调对应的 Skill 去改代码、跑测试、更新文档——全程不需要你重复解释“我们团队的规矩是……”。适合谁用三类人最受益一是多智能体协作的团队人和 AI 混编时规范就是共同语言二是长期维护的老项目规范文件比口口相传可靠三是做 Agent 编排的开发者SKILL.md 本质就是给 AI 看的“入职指南”。下面我从目录结构开始一步步拆给你看。2. TaoToken 前置准备让 Skill 调用有稳定的模型入口在写 SKILL.md 之前得先解决一个现实问题Skill 里的模型调用走哪里。SuperPowers 的技能注册本身不绑定模型但技能执行时比如让 AI 读规范、生成代码、跑校验需要一个稳定的 API 入口。我试过直接把各家模型的 key 硬编码进脚本结果换模型时改了七个文件还漏了一个导致线上 401。TaoToken 在这里的角色是统一模型网关一个 Base URL、一个 Key背后可以切不同模型。对 SDD 工作流来说这意味着 SKILL.md 里写的调用配置不用随模型更换而变。你只需要在环境变量里维护一份配置所有 Skill 共享。先拿 Key。访问 https://taotoken.net/api-keys 创建 API Key建议按项目分 Key比如sdd-openspec-prod、sdd-skill-dev方便后面排查是哪个环节出的问题。创建后复制保存页面只显示一次。拿到 Key 后在项目根目录建一个.env文件记得加进.gitignore# .env TAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELclaude-sonnet-4-20250514这里有个坑要提前说Base URL 不要带末尾斜杠也不要自己拼/v1。TaoToken 的 API 地址就是https://taotoken.net/apiSDK 会自动处理路径。我见过有人写成https://taotoken.net/api/v1/chat/completions然后报 404排查半天。如果你用的是 Claude Code 或 Cline 这类工具配置方式略有不同。Claude Code 需要在~/.claude/settings.json里配{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }Cline 的 MCP 配置则在cline_mcp_settings.json里后面第 3 节会给完整片段。Codex 用户改~/.codex/auth.json{ OPENAI_API_KEY: sk-你的key, OPENAI_BASE_URL: https://taotoken.net/api }三件套记住Base URL Key Model ID缺一个都跑不通。Model ID 建议先用claude-sonnet-4-20250514验证稳定后再换其他。想先确认模型通不通可以去 https://taotoken.net/models 用对话界面发一句“你好”能回就说明 Key 和网络都没问题。3. 可复制配置SKILL.md 目录结构 OpenSpec 模板 SuperPowers 注册这一节是全文最干的部分直接给能抄的配置。先看整体目录结构我按“规范层 / 技能层 / 资源层”三层组织project-root/ ├── openspec/ # 规范层 │ ├── specs/ │ │ ├── config-module.yaml # 配置模块规范 │ │ └── api-contract.yaml # 接口契约 │ └── changes/ │ └── add-version-field.yaml # 变更提案 ├── skills/ # 技能层 │ ├── skill-creator/ │ │ └── SKILL.md │ ├── config-validator/ │ │ ├── SKILL.md │ │ ├── scripts/ │ │ │ └── validate_config.py │ │ └── references/ │ │ └── schema.md │ └── superpowers.json # 技能注册表 └── .envOpenSpec 规范文件模板。以配置模块为例openspec/specs/config-module.yamlspec: name: config-module version: 1.2.0 description: 设备配置模块的字段定义与校验规则 entities: ConfigItem: fields: - name: key type: string required: true pattern: ^[a-z][a-z0-9_]{2,31}$ - name: value type: any required: true - name: version type: integer required: true min: 1 description: 配置版本号每次修改递增 - name: inherited type: boolean default: false description: 是否从父配置继承 constraints: - id: C001 rule: version 必须单调递增 severity: error - id: C002 rule: inheritedtrue 时 value 可为空 severity: warning changes: - id: add-version-field status: proposed affects: [ConfigItem.version] rationale: 支持配置回滚与审计这份规范的关键在于约束可被程序读取。constraints里的 rule 不是给人看的散文而是 Skill 执行时能解析的断言。changes段记录变更提案AI 改代码前先读这里避免“改了但没记录”。SKILL.md 模板。以config-validator为例--- name: config-validator description: 校验设备配置是否符合 OpenSpec 规范。当用户需要验证配置文件、检查字段类型、或确认版本号递增规则时使用。支持 YAML/JSON 格式输入输出违规项列表与修复建议。 --- # Config Validator ## 何时使用 - 用户提交配置文件需要校验 - CI 流水线中作为质量门禁 - 修改 OpenSpec 规范后回归验证 ## 输入 - config_path: 配置文件路径必填 - spec_path: OpenSpec 规范路径默认 openspec/specs/config-module.yaml - strict: 是否将 warning 视为 error默认 false ## 执行步骤 1. 读取 spec_path解析 entities 与 constraints 2. 读取 config_path逐字段比对类型与 required 3. 执行 constraints 中的 rule 断言 4. 输出 JSON 格式结果{ passed: bool, violations: [...] } ## 依赖资源 - scripts/validate_config.py核心校验逻辑 - references/schema.md字段类型对照表 ## 模型调用配置 - Base URL: https://taotoken.net/api - Model: claude-sonnet-4-20250514 - Key: 从环境变量 TAOTOKEN_API_KEY 读取注意 description 里把触发条件写全了——“校验配置”“检查字段类型”“确认版本号递增”都是用户可能说的原话。SuperPowers 靠这段文字决定是否激活该技能写窄了技能永远不触发写宽了到处误触发。SuperPowers 技能注册。skills/superpowers.json{ version: 1.0, skills: [ { name: config-validator, path: skills/config-validator/SKILL.md, enabled: true, triggers: [校验配置, validate config, 检查字段], priority: 10 }, { name: skill-creator, path: skills/skill-creator/SKILL.md, enabled: true, triggers: [创建技能, 生成 SKILL.md], priority: 5 } ], model: { base_url: https://taotoken.net/api, model_id: claude-sonnet-4-20250514, api_key_env: TAOTOKEN_API_KEY } }如果你用 Cline 的 MCP 模式配置写在cline_mcp_settings.json{ mcpServers: { superpowers: { command: node, args: [./skills/superpowers-server.js], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-你的key, TAOTOKEN_MODEL: claude-sonnet-4-20250514 } } } }三件套再次出现Base URL、Key、Model ID。Cline 里如果只填了 Key 没填 Base URL会默认走官方地址然后报local proxy failed这个错后面第 5 节细说。4. 验证请求从规范到技能落地跑一遍配置写完不验证等于没写。这一节我带你跑一次完整流程改规范 → 触发技能 → 校验通过。先准备一个待校验的配置文件test-config.yamlitems: - key: device_name value: sensor-01 version: 1 inherited: false - key: sample_rate value: 100 version: 0 inherited: false注意第二条version: 0这违反了规范里min: 1的约束我们看技能能不能抓出来。第一步确认模型入口通。用 curl 发一个最小请求curl -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: $TAOTOKEN_API_KEY \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-20250514, max_tokens: 100, messages: [{role: user, content: 回复 OK}] }返回里如果有content: [{type: text, text: OK}]说明 Key 和 Base URL 都对。如果返回 401先检查 Key 有没有多余空格如果返回model not found去 https://taotoken.net/models 确认 Model ID 拼写。第二步手动跑校验脚本。先不经过 AI直接执行scripts/validate_config.py# scripts/validate_config.py import yaml, json, sys, os def load_spec(path): with open(path) as f: return yaml.safe_load(f) def validate(config_path, spec_path): spec load_spec(spec_path) with open(config_path) as f: config yaml.safe_load(f) violations [] entity spec[entities][ConfigItem] field_map {f[name]: f for f in entity[fields]} for idx, item in enumerate(config.get(items, [])): for fname, fdef in field_map.items(): if fdef.get(required) and fname not in item: violations.append({ index: idx, field: fname, rule: required, severity: error }) if fname in item and min in fdef: if item[fname] fdef[min]: violations.append({ index: idx, field: fname, rule: fmin{fdef[min]}, actual: item[fname], severity: error }) return {passed: len(violations) 0, violations: violations} if __name__ __main__: result validate(sys.argv[1], sys.argv[2]) print(json.dumps(result, indent2, ensure_asciiFalse)) sys.exit(0 if result[passed] else 1)执行python scripts/validate_config.py test-config.yaml openspec/specs/config-module.yaml预期输出{ passed: false, violations: [ { index: 1, field: version, rule: min1, actual: 0, severity: error } ] }第三步让 AI 通过技能自动修复。在支持 SuperPowers 的客户端里输入“用 config-validator 校验 test-config.yaml把违规项修掉”。AI 会先读 SKILL.md 了解流程再读 OpenSpec 规范拿到约束然后调脚本跑校验最后根据 violations 改文件。修复后的test-config.yaml里version变成 1再跑一次脚本返回passed: true。这一步验证了三件事规范文件能被解析、技能能被触发、模型入口稳定。三者缺一SDD 工作流就断链。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth配置类问题 90% 集中在四个报错上我按出现频率排。401 Unauthorized。最常见的原因是 Key 没生效。检查顺序.env文件有没有被加载Python 用python-dotenvNode 用dotenv环境变量名有没有拼错TAOTOKEN_API_KEY不是TAOTOKEN_KEYKey 有没有过期或被删。如果用的是 Claude Codesettings.json里的ANTHROPIC_API_KEY和 shell 里的TAOTOKEN_API_KEY是两个变量别混。还有一种隐蔽情况Key 复制时带了换行符用echo $TAOTOKEN_API_KEY | wc -c看长度对不对。local proxy failed。这个错通常出现在 Cline 或 Claude Code 里本质是客户端想走本地代理但代理没起来。如果你没配代理检查settings.json里有没有残留的HTTP_PROXY或HTTPS_PROXY环境变量。TaoToken 的 API 地址是直连的不需要额外代理配置。把ANTHROPIC_BASE_URL明确写成https://taotoken.net/api就能绕过本地代理逻辑。reading choices 报错。完整报错一般是Cannot read properties of undefined (reading choices)说明返回体里没有choices字段。两种可能一是 Base URL 写成了 OpenAI 格式但实际调的是 Anthropic 格式接口或者反过来。TaoToken 同时支持两种格式但路径不同——Anthropic 格式走/v1/messagesOpenAI 格式走/v1/chat/completions。二是 Model ID 写错返回了错误对象而不是正常响应。先curl确认返回结构再改客户端配置。OAuth 相关报错。Claude Code 首次启动会尝试 OAuth 登录如果你已经配了 API Key需要在settings.json里加forceApiKey: true否则它会优先走 OAuth 流程然后失败。Codex 的auth.json里如果同时有OPENAI_API_KEY和 OAuth token也会冲突删掉 OAuth 相关字段即可。排查通用套路先 curl 后客户端先环境变量后配置文件。curl 通了说明服务端没问题问题在客户端配置curl 不通说明 Key 或网络有问题。这个顺序能省一半时间。6. 把规范编程工作流跑成日常习惯最后说点实操层面的经验。SDD 工作流最大的敌人不是技术是规范写完就没人更新。我见过团队把 OpenSpec 文件建得漂漂亮亮两周后代码和规范完全对不上AI 读了规范反而生成错误代码。三个习惯能避免这个问题。第一规范变更必须走 changes 段每次改specs/下的文件同步在changes/里加一条提案记录改了什么、为什么改。第二SKILL.md 的 description 定期回看用户说话方式会变触发词也要跟着调我一般每月扫一遍触发日志把没命中的说法补进去。第三校验脚本进 CIvalidate_config.py这种脚本不要只靠人手动跑挂到 pre-commit hook 里规范违规直接挡在提交前。如果你想把技能调用固定到长期项目上Coding Plan 比按量付费更省心模型入口和额度都稳定。需要看完整接入文档的话https://taotoken.net/doc 里有各客户端的配置示例。模型对话界面在 https://taotoken.net/models 调 SKILL.md 的 description 时可以用它快速试触发效果。这套流程跑顺之后你会发现 AI 不再是“每次都要重新解释需求”的工具而是读得懂团队规矩的协作者。规范是契约技能是手脚模型入口是神经三者接上SDD 才算真正落地。