导读
很多团队会把「AI 该怎么干活」写进项目的 CLAUDE.md 或一份很长的工作流文档:任务怎么分级、需求怎么拆、做完要跑哪些检查、怎么交付。用了一段时间后,我们碰到了三个问题:
- 复制走样:流程和项目特有的东西(技术栈、设计工具、接口平台、验证平台)混在一起,新项目只能整份复制再手工删改,改进也没法同步到其他项目。
- 只是文字:流程里说「需求要拆成任务卡」「中断要写交接记录」,但新项目里根本没有这些文件和目录,流程落不下来。
- 靠 AI 自觉:「改完代码要跑静态分析」写得再清楚,AI 也有漏掉的时候,而没人会发现。
我们的解法是把工作流做成一组 Claude Code 插件:流程写成按需触发的 skill,项目差异由一个 init 命令自动探测并生成配置和文档骨架,关键检查用脚本和钩子兜底。现在新项目接入只需两步:装插件、跑一次 /workflow-core:init。
本文会讲清楚:Claude Code 插件的各组件适合放什么规则、插件如何分层、工作流的核心细节、用哪些机制保证每个项目执行一致,以及过程中踩过的坑。示例技术栈是 Flutter,但思路适用于任何栈。
Claude Code 插件原理
一个插件就是一个目录:.claude-plugin/plugin.json 声明元信息和依赖,其余组件按约定放在子目录里。做工作流插件时,关键是弄清楚每种组件「什么时候生效」,再决定规则放哪里。
| 组件 | 位置 | 什么时候生效 | 适合放 |
|---|---|---|---|
| Skill | skills/<名称>/SKILL.md | 只有 frontmatter 里的 description 常驻上下文;模型判断用得上,或用户输入 /<插件>:<名称> 时才加载正文 | 触发时才需要展开的流程:需求拆解、失败分类、交接 |
| Hook | hooks/hooks.json | 在生命周期事件(工具调用前后、回合结束 Stop 等)由 Claude Code 执行,不依赖模型自觉 | 必须做到、可以自动判断的检查 |
| MCP server | .mcp.json | 插件启用即连接,提供工具 | 外部工具接入(设计稿、文档查询) |
| 脚本与模板 | 任意目录,skill 里用 ${CLAUDE_PLUGIN_ROOT} 引用 | skill 或 hook 调用时 | 确定性的探测、检查、文件骨架 |
两个容易忽略的点:
- skill 不适合放硬规则 。「不自动提交」「保留用户已有修改」这类每次都要遵守的规则,放进 skill 会因为没触发而漏掉,应该留在项目的
CLAUDE.md/AGENTS.md(常驻上下文);真正不能漏的用 hook。 ${CLAUDE_PLUGIN_ROOT}只在 skill、hook、MCP 配置中替换 。写进项目的AGENTS.md不会生效,所以项目配置里只写「用哪个脚本」,路径由 skill 解析。
分发与依赖 :一个 git 仓库加上 .claude-plugin/marketplace.json 就是一个 marketplace,可以收录多个插件。插件在 plugin.json 里声明 dependencies,安装时自动装上;依赖另一个 marketplace 的插件时,需要在自己的 marketplace.json 里用 allowCrossMarketplaceDependenciesOn 把对方加入白名单。
安装范围决定插件在哪里生效:
| 范围 | 参数 | 写入位置 | 适合 |
|---|---|---|---|
| user | 默认 | ~/.claude/settings.json | 与技术栈无关的通用流程,装一次处处可用 |
| project | --scope project | 项目 .claude/settings.json,进 git | 和项目绑定的技术栈、工具插件,团队共享 |
| local | --scope local | 项目 .claude/settings.local.json,不进 git | 个人试用 |
架构:按维度拆插件
我们没有做一个大而全的插件,而是按「通用流程 / 技术栈 / 设计工具 / 接口工具」四个维度拆成多个插件,放在同一个 marketplace 里,项目按自己的组合安装。
bash
ai-dev-workflow/ # 一个 git 仓库 = 一个 marketplace
├── .claude-plugin/marketplace.json
└── plugins/
├── workflow-core/ # 通用流程:所有项目都装
├── stack-flutter/ # 技术栈:将来还有 stack-react、stack-vue
├── design-pixso/ # 设计工具:将来还有 design-figma
├── api-apifox/ # 接口工具
└── preset-flutter-pixso-apifox/ # 组合包:只有 dependencies
为什么不做一个大插件:每个 skill 的 description 都常驻上下文。Flutter 项目装着 React、Vue 的 skill,既浪费上下文,又可能触发错(问「组件状态怎么管」却加载了 React 的规范)。拆开后各维度独立发版,统一入口由 marketplace 和 preset 提供。
为什么设计工具、接口工具单独成维度 :它们和技术栈是正交的------同样是 Flutter 项目,设计稿可能在 Pixso 也可能在 Figma。workflow-core 里只写抽象步骤(「从项目指定的设计源读取设计」),具体工具的读法由 design-* 插件填充,项目配置声明选用哪个。
规则冲突时的优先级(写在入口 skill 里):
- 用户本次明确指令
- 项目
AGENTS.md的「工作流配置」与项目docs/ - 技术栈 / 设计 / 接口插件的惯例
workflow-core的通用流程- 其他通用技能插件(如 Superpowers、官方 Dart and Flutter)的建议
一条规则放插件还是留项目 :问一句「换一个同技术栈的项目还成立吗?」。比如「默认只验证 Android」是某个项目的选择,应该留在项目;「改依赖要同时检查 pubspec.lock」对所有 Flutter 项目都成立,可以放进 stack-flutter。脚本的标准更严:只服务 AI 工作流、与具体项目无关、项目离开它照样能运行,三条都满足才放插件。构建、发布、代码生成、提交钩子这类脚本留在项目,否则没装插件的 CI 和同事就跑不了。依赖方向始终是「插件 → 项目配置 → 项目」,反过来不行。
工作流核心
每个任务从分档开始:轻量和标准档直接开工,完整档先做需求拆解并取得批准;验证失败回到实施,通过才交付。每个阶段对应 workflow-core 里的一个 skill,入口 skill workflow 给出这张阶段地图。

虚线框是规划中的阶段;底部横条表示交接可在任何阶段发生。不是每个任务都走完全程:轻量任务通常只走 0 → 4 → 5 → 6,只整理需求的任务停在 1。下面是几个最核心的约定。
三档分级:按风险分,不按代码行数
| 档位 | 适用 | 最小产物 | 批准 |
|---|---|---|---|
| 轻量 | 文案、文档、局部样式、预期明确的小 Bug | 会话或已有 Issue | 无 |
| 标准 | 边界明确、复用现有架构的小功能 | 卡或 Issue 内 3~5 步计划 + 证据 | 用户要求实施且规则清楚即可 |
| 完整 | 鉴权/安全、持久化迁移、对外契约变化、跨模块、关键规则不确定 | proposal / 规格 / tasks | 提案批准后分段实施,每段停下汇报 |
完整档条件优先;标准档做到一半发现契约变化,就保留已有证据、升级到完整档。分档的意义是把流程成本和风险对齐:改个文案不写提案,改登录态不能跳过批准。
需求拆解:同一事实只维护一处
PRD 拆成「可独立验收的业务结果」而不是「前端 / 后端 / 测试」。业务规则只写在需求说明,产品状态只写在模块卡,设计节点只写在设计索引,技术任务只写在规格 tasks,其他位置只引用。缺项和冲突用统一格式登记,不让 AI 静默选一方:
xml
- 待确认:<具体缺项>|影响:<阻塞的子需求>|负责人:<姓名或待指定>|恢复条件:<取得什么后继续>|来源:<问题编号或链接>
完成勾选只与「已验收」一致:代码合并、技术 tasks 完成都不能勾产品完成。
验证失败先分类再动手
AI 最常见的问题之一,是把测试失败一律归为「和本次改动无关」。verify 要求先保留证据、对照同环境同命令的基线,再归入七类之一:本次回归、环境或工具问题、既有失败、原因待定位、需求或接口不明确、超出范围、尝试无进展。没有可比基线就标「原因待定位」,工具缺失不能写成失败或通过,连续两轮无新证据就换思路或交接。
统一交付:结论 + 五项
markdown
结论:<实际状态,不把代码完成写成产品已验收>
1. 场景:本次交付的业务/验收场景
2. 文件:实际修改的文件及用途
3. 验证:实际执行的命令/操作、结果、对应版本
4. 剩余:失败、未验证、阻塞及下一步
5. 同步:需求卡、tasks、规格、交接是否已更新
配套的状态口径互不替代:实施完成待验证 / 可评审 / 可合并 / 已上线 / 受阻。只报告实际执行过的验证,Mock 通过不写成真实联调通过。
中断交接:状态写进仓库,不靠聊天记忆
任务没做完就要换会话时,必须把快照写进仓库(目标、分支与 HEAD、工作区、进度、关键决定、验证、下一步)。接手时按固定步骤恢复:读规范和快照 → 比对 Git 状态 → 核实快照里的进程是否还在 → 重跑最小基线 → 从第一项未完成工作继续;并且不为恢复快照自动 reset、stash 或覆盖文件。
如何保证工作流一致
光有流程文字不够。我们用四个机制,分别解决「每个项目情况不同」「流程没有载体」「文档格式会走样」「AI 会漏做检查」四个问题。
| 机制 | 解决的问题 | 做法 |
|---|---|---|
| init + 工作流配置 | 插件不能写死任何项目的路径和命令,但让每人手写配置又不现实 | 脚本只读探测项目,只问识别不了的项,生成配置提交进 git |
| 文档骨架 | 流程要求「写任务卡」「登记待确认」,新项目却没有这些文件 | 固定默认目录结构,按需生成,用探测到的事实填写 |
| 文档规范检查 | 格式由插件定义,但人和 AI 都会写歪 | 插件自带只读脚本,本地和 CI 跑同一份 |
| Stop 钩子 | 「改完代码要跑静态分析」只靠 AI 自觉 | AI 结束回合前自动分析改动文件,有错误就让它先修 |
1. init:自动探测,只问不知道的
插件通过项目 AGENTS.md 里的「工作流配置」小节了解项目:产品文档在哪、各档跑什么命令、默认验证哪个平台、用什么设计和接口工具。这份配置按项目写一次、提交进 git,团队和其他 Agent 共用。
大部分配置项都能从仓库里推断,所以 init 先跑一个只读探测脚本:
makefile
stack: flutter
flutter_platforms: android,ios,web
spec_tool: openspec (6 个进行中 change)
api_tool: apifox (.apifox/settings.json, projectId=...)
design_tool: pixso
check_entry: scripts/check.py
ci: check.yml
existing_workflow_config: -
技术栈看 pubspec.yaml / package.json,规格工具看有没有 openspec/,接口工具看 .apifox/,设计工具看文档里的设计链接,验证命令看脚本、Makefile、package.json scripts 和 CI 配置。探测不出的(默认验证哪个平台、多个设计文件哪个是权威)才集中提问,并给推荐值。写入前展示「配置项 | 值 | 依据」,每个值都注明来自哪个文件;命令只写仓库里真实存在的,不编造。已有配置时进入更新模式,只改有变化的行。
2. 文档骨架:给流程一个载体
流程说明在插件里,项目只放流程的输入和产物。我们固定了一套默认结构(老项目可以在配置里映射到自己的路径),但不一次铺满空文件,而是在第一次需要时生成:
| 文档 | 什么时候生成 |
|---|---|
| 项目首页、需求说明(含待确认问题表)、版本任务总览 | init |
| 代码规范、架构规范、验证规范 | init |
| 设计索引 / UI 规范 / 接口联调约定 | init,分别在有设计工具 / 有界面 / 有后端接口时 |
| 模块任务卡 任务/<模块>.md | 需求拆解首次拆出该模块时 |
| 交接记录 handoffs/.md | 第一次跨会话交接时 |
三条规则让骨架不变成文档负担:已有同类文档只做映射不新建;已有文件一律不覆盖;模板里的占位符用探测到的事实填写------验证规范直接写入真实的检查命令,架构规范按现有目录推断分层并逐行标「待确认」,不留一堆「请填写」。生成后立即跑文档检查,链接必须全部通过。
3. 文档规范检查:格式在哪,检查就在哪
任务卡必填字段、「待确认」五段格式都是插件定义的,如果检查脚本留在各个项目里,插件一改格式,各项目的脚本就过时了。所以检查脚本 check_docs.py 随插件发布:
- 检查本地链接与锚点、任务卡必填字段、待确认记录格式;只读、只用 Python 标准库。
- 路径从「工作流配置」读取,可用参数覆盖。
- 退出码区分 0 通过、1 未通过、2 执行受阻------工具缺失不能被当成通过。
CI 里没有 Claude 插件,就在 CI 里签出插件仓库的固定 tag 运行同一份脚本,版本可复现(写法见下一节)。
4. Stop 钩子:AI 漏了也会被拦下
「改了代码必须跑静态分析」分三层保证:
- 规则层 (
verify/deliverskill):改了代码,交付前必须有格式检查、静态分析、相关测试三项实际结果;缺一项,结论只能写「实施完成,待验证」。让 AI 知道必须做。 - 命令层 (
stack-flutter的flutter_check.py):项目没配置检查命令时的默认值,只格式检查改动的手写文件、排除.g.dart等生成文件。让 AI 有命令可用。 - 强制层(Stop 钩子):让 AI 漏了也会被拦下。
钩子注册在 hooks/hooks.json:
bash
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "python3",
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/stop_analyze.py"],
"timeout": 120
}]
}]
}
}
AI 每次准备结束回合时,脚本找出相对 HEAD 改动的手写 Dart 文件,跑 dart analyze。有 error 就输出:
swift
{"hookSpecificOutput": {"hookEventName": "Stop",
"additionalContext": "本次改动的 1 个 Dart 文件中有 1 个错误,结束前请先修复:\n- lib/app.dart:99:19 A value of type 'String' can't be assigned to a variable of type 'int'."}}
Claude Code 会把这段反馈交给 AI,它继续修复而不是结束。几个设计要点:
- 防死循环 :输入里的
stop_hook_active为 true,说明已经因为钩子继续过一次,这时只用systemMessage提示用户,不再阻止。 - 故障放行:不是 Flutter 项目、没改 Dart 文件、分析器不可用、超时(90 秒)都直接放行,钩子自己出问题不能卡住会话。
- 只拦 error、只看改动文件:没改 Dart 文件时 0.09 秒放行,有改动时分析约 1.4 秒;耗时长的测试仍交给规则层。
三层各管一件事:规则让 AI 知道必须做,命令让它有东西可用,钩子保证漏了也会被拦下。换成 Vue/React 项目,只需在对应技术栈插件里用 tsc --noEmit 或 eslint 实现同样的钩子。
集成方式
从零接入一个项目分五步:添加 marketplace、安装插件、跑 init、团队分发、接入 CI。
1. 添加 marketplace(每台机器一次)
xml
claude plugin marketplace add <你的 GitHub 用户名>/<仓库名>
2. 安装插件。通用流程装用户级,所有项目可用;技术栈和工具插件按项目装,或直接装组合包:
sql
claude plugin install workflow-core@ai-dev-workflow
claude plugin install preset-flutter-pixso-apifox@ai-dev-workflow --scope project
组合包是一个只有 dependencies 的插件,它还依赖了三个外部插件:官方 marketplace 的 context7(第三方库文档)、superpowers(调试、TDD 等通用技能),以及 Flutter 团队的 dart-flutter(Flutter/Dart 技能 + Dart MCP server)。后者来自独立的 marketplace,需要先添加:
bash
claude plugin marketplace add flutter/agent-plugins
3. 接入项目 :在项目里的 Claude Code 会话中执行 /workflow-core:init,确认生成的配置和文档清单。之后正常描述需求即可,skill 会自动触发;也可以手动调用,如 /workflow-core:tiering、/workflow-core:deliver。
4. 团队分发 :在项目 .claude/settings.json 写入 marketplace 和启用的插件并提交,成员打开项目、信任目录后会收到安装提示。依赖的外部 marketplace 也要列进去,因为依赖解析不会自动添加 marketplace:
json
{
"extraKnownMarketplaces": {
"ai-dev-workflow": { "source": { "source": "github", "repo": "<用户名>/<仓库名>" } },
"dart-flutter": { "source": { "source": "github", "repo": "flutter/agent-plugins" } }
},
"enabledPlugins": { "preset-flutter-pixso-apifox@ai-dev-workflow": true }
}
5. 接入 CI:CI 里没有 Claude 插件,签出插件仓库的固定 tag 运行文档检查:
yaml
- uses: actions/checkout@v4
with:
repository: <用户名>/<仓库名>
ref: workflow-core--v0.5.0
path: .ai-workflow
- run: python3 .ai-workflow/plugins/workflow-core/scripts/check_docs.py --root .
如果项目已有自己的检查入口,也可以让它在内部转调插件脚本,按「环境变量指定目录 → CI 签出目录 → 本机插件缓存」的顺序查找,都找不到时报「执行受阻」而不是通过。
发版与更新 :plugin.json 里写了 version,已安装的用户就会锁在这个版本。每次改内容都要升版本,推送后在插件目录执行 claude plugin tag --push,生成 <插件名>--v<版本> 的 tag;用户侧执行 claude plugin marketplace update 和 claude plugin update 拿到新版。维护者自己可以从本地路径添加 marketplace,插件就地加载、不受版本锁定,改完执行 /reload-plugins 即可。
踩坑与经验
下面这些坑,任何做 Claude Code 插件的人都可能遇到。
| 现象 | 原因 | 解法 |
|---|---|---|
| 推送了新内容,同事更新后还是旧版 | plugin.json 的 version 把用户锁在该版本 | 改内容就升版本并打 tag |
| 换个项目插件显示 disabled,也没有 /workflow-core:init | 之前用 --scope local 安装;marketplace 是用户级的所以能列出插件,但启用只记录在原项目 | 通用插件装 user 范围 |
| 依赖内置插件目录里的插件失败 | 插件虽然出现在内置 Anthropic 目录里,但 CLI 无法按名称从内置目录解析 | 依赖它自己仓库的 marketplace,并加入跨 marketplace 白名单 |
| 缺少外部 marketplace 时插件整个不加载 | 声明了未满足依赖的插件会被禁用 | 外部依赖写在没有内容的组合包上,不写在有钩子的技术栈插件上,失败也不连带 |
| 在 git 钩子里调用 Flutter,SDK 版本变成 0.0.0-unknown | 钩子环境带着 GIT_DIR,Flutter 读到了项目仓库的 git 元数据 | 调用 flutter 前 unset GIT_DIR GIT_INDEX_FILE |
| Stop 钩子可能无限阻止结束 | 既有错误修不好时每轮都会触发 | 检查 stop_hook_active,第二轮只提示;工具异常一律放行 |
| 项目配置里的 ${CLAUDE_PLUGIN_ROOT} 不生效 | 变量只在 skill、hook、MCP 配置中替换 | 项目配置只写用哪个脚本,路径由 skill 解析 |
| init 写好了配置,团队却拿不到 | 项目 .gitignore 忽略了 AGENTS.md | init 写入前用 git check-ignore -v 检查,告知用户由其决定 |
| claude -p --allowedTools Bash "提示词" 报「没有输入」 | --allowedTools 是变参,把后面的提示词也当成了工具名 | 提示词走 stdin:`echo "..." |
除了具体的坑,还有三条更通用的经验:
- 先分清「流程」和「事实」。第一版我们把「默认只验证 Android」「Apifox 操作边界」都写进了通用层,换一个项目就不成立。每条规则都问一句「换个项目还成立吗」。
- 用真实项目试跑,而不是只看文字 。用
claude -p --plugin-dir <插件目录>在仓库副本上非交互地跑一遍 skill,再检查生成的文件;.gitignore忽略AGENTS.md的问题就是这样发现的。 - 用干净配置模拟新成员 。
CLAUDE_CONFIG_DIR=/tmp/claude-fresh claude启动一个全新环境,走一遍安装流程,能看到哪些前置步骤没写进 README。
后续改进方向
目前工作流覆盖了「需求 → 拆解 → 开发 → 验证 → 交付」,下一步是补齐测试侧的阶段,并把同样的一致性机制推广到更多技术栈。
| 方向 | 计划 |
|---|---|
| 代码评审阶段 | 新增 code-review skill:评审范围、严重度口径、结果如何写进交付五项;可依赖官方 code-review 插件 |
| 集成测试阶段 | 新增 integration-test skill:从任务卡的验收场景生成用例 → 准备环境与测试数据 → 执行 → 把结果回写到卡片;接口场景交给 Apifox 等接口平台执行 |
| 更多技术栈 | stack-react、stack-vue,用 tsc --noEmit / eslint 实现同样的 Stop 钩子兜底 |
| 更多设计工具 | design-figma,可依赖 Figma 官方插件 |
| 流程度量 | 统计钩子拦截次数、交付中「待验证」的比例,用数据判断哪些规则真正起了作用 |
如果你也在给团队定制 AI 工作流,最值得借鉴的可能不是具体规则,而是这个分工:流程放 skill,硬规则放常驻配置,必须做到的交给脚本和钩子,项目差异交给一个能自动探测的 init。