写给每一个用 Claude Code 做工作流的人

能跑起来只是起点,能持续跑下去才是产品。

很多工作流在最初几天表现很好。然后你会发现:文件被覆盖、步骤被跳过、失败无法复盘、同样的坑反复踩。 这些不是"用法不对",而是缺少一套系统性的治理结构。WorkflowProgram 就是为了解这类问题而存在的。

这份教程会从最常见的问题出发,一步步带你理解 WorkflowProgram 的每一层设计为什么存在、怎么协作、以及你能从中借鉴什么。

一次完整运行的主链
需求 规格 候选 受控写入 运行 判定 回流
四句话概括设计信念
  • 要有一份统一的机器可读设计真源
  • 设计、执行、验证、回流要分层
  • 目标项目写入必须受控,绝不直接覆盖
  • 每次运行必须留下结构化证据

第一步:看见问题

工作流编排最常见的 8 个失控点

如果你做过 Claude Code 工作流,下面这些场景你大概率遇到过至少三个。 WorkflowProgram 不是凭空发明概念,它的每一层设计都是为了回应某个具体的失控场景。

1. 没有统一真源

语义散在技能说明、聊天记录和人工约定里。改了文档不等于改了行为,改了行为不等于更新了文档。

解决思路:先收口到一份机器可读的设计真源,再让其他说明文档从它派生。

2. 编排顺序靠模型记忆

这一轮先做设计再写文件,下一轮可能直接跳到写文件。步骤漏掉、重复或者乱序,全靠运气。

解决思路:把关键顺序沉到确定性程序里,让步骤推进不再依赖模型“记住”。

3. 目标项目被直接写坏

模型一旦直接覆盖目标文件,用户手工维护的内容可能丢失,冲突和回退都变得很难处理。

解决思路:先把结果写到隔离候选区,再做受控应用;冲突时保留证据,不静默覆盖。

4. 失败后无法分层定位

最后只知道"失败了",但不知道问题出在设计层、执行层、环境层还是判定层。

解决思路:把设计、执行、判定、补证据拆成独立层,让每一层都能单独下结论。

5. 运行证据不足

只有最终产物,没有上下文快照、状态记录、事件记录和运行报告。出了问题只能猜。

解决思路:把每次运行的上下文、状态、事件和报告都落成结构化证据。

6. 验证只看退出码

"脚本跑完了"不等于"按约束执行成功了"。退出码 0 只能说明没有 crash,不能说明满足了业务约束。

解决思路:把“运行约束”和“测试约束”单独定义,再由独立判定器给出结论。

7. 经验不会回流

这次踩的坑、总结的教训留在聊天记录里,下一轮还是从零开始。

解决思路:把单次总结和长期规则分开管理,让经验进入下一轮运行。

8. 自然语言入口漂移

同一句话这次落到 develop,下次落到 validate。入口不稳定,后面的行为就不可预期。

解决思路:先做入口识别和意图路由,再进入对应主流程。

第二步:理解设计哲学

工作流不是一段大提示词(prompt),而是四层职责

很多工作流一开始就是“写一个技能说明,再补几个代理说明,最后改一下设置”。 这种做法能快速启动,但很难持续维护。原因是它把四件本质不同的事情混在了一起。

01

真源

先有一份机器可读的设计真源,再从它生成给人读的说明和维护文档。 想改行为,先改真源;不要反过来改说明文档试图影响实际执行。

02

控制面

要有一层专门负责步骤推进、状态转移、边界检查和证据落盘。 模型在节点内理解和生成,但节点之间怎么切换应该由程序决定。

03

验证层

生成者不能同时做裁判。要有独立的验证层基于证据和约束给出结论。 生成成功不等于验证通过。

04

闭环层

单次经验和长期规则要分开管理。 前者记录这次学到了什么,后者决定下一轮有哪些事必须做、绝不能做。

为什么是四层而不是更多? 因为“能跑”到“可维护”之间,至少隔着这四件事:统一真源、稳定控制、独立验证、经验回流。少一层不完整,多一层通常会过度设计。

第三步:划清边界

为什么必须区分插件根目录(PLUGIN_ROOT)、目标根目录(TARGET_ROOT)、运行根目录(RUN_ROOT)

如果输入、输出、证据全混在一个目录里,你很快就会分不清"谁是参考、谁是交付、谁是中间态"。 三根目录是 WorkflowProgram 最基础的边界契约。

PLUGIN_ROOT

WorkflowProgram 自身的能力仓:skills、agents、脚本、模板。它只被读取,永远不被修改。

实际路径:dist/plugin/

TARGET_ROOT

用户的目标项目。最终交付的 .claude/ 资产在这里。只能通过 managed apply 写入,不能直接覆盖。

实际路径:用户项目根目录

RUN_ROOT

单次运行的隔离空间。spec、候选资产、状态、事件、报告全在这里,运行结束后可完整回溯。

实际路径:TARGET_ROOT/.workflowprogram/runs/<run-id>/

PLUGIN_ROOT skills, scripts, templates 只读 · 能力来源 TARGET_ROOT .claude/ 最终交付 受控写入 · 不直接覆盖 RUN_ROOT state, events, report 隔离空间 · 完整证据 读模板 落证据

第四步:理解生命周期

为什么是 S0S6

阶段不是为了多几个数字好看,而是为了让每一段职责都能被独立验证、回退和复盘。 设计和执行混在一起,最后出了问题只能从头来过;拆开之后,你可以精确定位到"在哪一步、因为什么"出了问题。

S0路由与目标准备
S1需求澄清
S2上下文研究
S3设计与审批
S4受控写入
S5验证判定
S6经验回流

不同意图不需要走完所有阶段。四种核心意图各有自己的阶段路径:

developS1 → S2 → S3 → S4 → S5 → S6

从需求到交付的完整链路

auditS5 → S6

对已有 workflow 做结构审计

validateS5

只做一次验证判定

iterateS6

从 lessons 中提炼改进

关键判断: 生成成功不等于验证通过(S4 ok ≠ S5 ok);验证失败不等于这次运行没价值(S5 fail 但 S6 可以回流 lessons)。

第五步:看懂运行机制

AI 负责理解和生成,Python 负责控制面

WorkflowProgram 做了一个关键判断:需要稳定执行、稳定落盘、稳定复验的部分,不能留在 prompt 里

所以两个角色各有分工:

  • AI:理解需求、补充设计、在每个节点内生成候选资产。
  • Python:路由意图、校验 spec、managed apply、状态转移、证据落盘、S5 判定。

具体地说,workflow-entry.py 把下面这条脚本链串成固定顺序,不依赖模型"记得下一步该做什么":

用户请求 orchestrate develop / audit workflow-entry runner / judge workflow-entry.py 固定脚本链 1. validate-workflow-spec.py — 校验 spec 结构 2. generate-workflow-view.py — 生成人类可读视图 3. managed-assets.py — 候选写入 4. workflow-runner.py — 控制面执行 5. validate-run-state.py — 运行后状态校验

第六步:分清入口关系

为什么要先做入口识别,再进入主流程

很多工作流一开始只有一个入口:用户说一句话,模型就直接开始做事。 这样的问题是,同类请求可能落到不同流程,入口行为会越来越不稳定。 更稳的做法是先做一层“入口识别”,把请求归到正确的主流程,再继续往下执行。

方案层:入口识别要解决什么

  • 同一句自然语言请求,不应该这次走开发,下次走验证。
  • 显式入口和自然语言入口,最终应当收口到同一套阶段语义。
  • 入口层应该留下“为什么走这条路径”的证据,方便后续复盘。

当前实现怎么落这件事

  • 自然语言默认先进入 workflowprogram-orchestrate
  • 显式叶子入口不会再回跳到总控技能。
  • 但入口脚本仍会再次跑路由检查,用来留证据、检查入口和请求是否冲突。
先记住一句话: 入口层的职责不是“开始干活”,而是“先判断该走哪条主流程,并把这个判断留下来”。
自然语言请求 workflowprogram- orchestrate 叶子入口 entry 显式 /develop 叶子入口 workflow-entry.py 内部再跑 route-intent.py 用来留证据,不是回跳 orchestrate

第七步:理解写入安全

为什么要先写候选区,再做受控应用

这是很多人第一次听到会觉得“多此一举”的设计。但只要你经历过一次“模型把你手工维护的配置覆盖了”, 你就会明白:写入安全是工作流工程化的硬分水岭。

先看问题:为什么不能直接写目标项目

  • 用户手工维护的文件容易被误改或丢失。
  • 冲突发生时没有中间态证据,无法恢复。
  • 事后无法区分哪些文件是工具写的、哪些是人写的。

更稳的方案

  • 先把结果写到隔离候选区,不直接碰目标项目。
  • 再做一次变更计划,明确哪些文件是创建、更新、冲突。
  • 最后再执行受控应用。冲突时保留副本,不静默覆盖。
  • 持续记录哪些文件属于工具托管。
先记住一句话: “生成结果”和“把结果写进目标项目”不是一回事。前者可以大胆试,后者必须受控。

到了当前实现里,这条受控写入链具体落在这些文件和产物上:

当前实现里的动作

  • managed-assets.py plan:生成变更计划
  • managed-assets.py apply-staged:执行受控应用
  • managed-files.json:记录托管文件清单

当前实现里的关键产物

  • RUN_ROOT/outputs/candidate/:候选资产区
  • managed-change-plan.json:变更计划
  • managed-change-result.json:变更结果

第八步:分清三层验证

生成者不能同时做自己的裁判

如果"生成"和"验证"是同一个角色负责,生成成功就容易被误当成验证通过。 WorkflowProgram 把验证拆成三层,每层有明确的职责边界:

A

执行约束层

先回答“这次运行在形式上是不是合格的”。例如有没有越界写入、有没有留下最小证据、状态和失败类型是不是落在允许范围内。

B

结果判定层

再回答“这次运行算不算真正达成目标”。这层不看单一退出码,而是综合入口、边界、流程、产物和失败映射来下结论。

C

动态补证据层

最后补上真实运行场景中的动态证据,确认这套设计不仅在静态结构上成立,也能在实际运行时留下足够信息。

先记住这三层各自回答的问题: 执行约束层回答“能不能这样跑”,结果判定层回答“这样跑算不算通过”,动态补证据层回答“真实运行时有没有留下足够证据”。

到了当前实现里,这三层分别落在这些角色上:

当前实现映射

  • workflow-runner.py:执行约束层
  • workflowprogram-validate / workflow-s5-judge.py:结果判定层
  • runtime_smoke.py:动态补证据层

你最终会看到的核心证据

  • 状态快照
  • 事件记录
  • 运行 transcript
  • 验证报告
  • 机器可读判定摘要
RUN_ROOT/state.json控制面状态快照
RUN_ROOT/events.jsonl事件流(可重放)
RUN_ROOT/transcript.md运行过程 transcript
validation-runtime-report.mdS5 判定报告(人类可读)
s5-validation-summary.jsonS5 判定摘要(机器可读)

第九步:理解测试

测试环节是怎么证明“工作流真的按定义和约束执行”的

WorkflowProgram 的测试不是只看命令退出码,而是分层证明: 设计是不是合法、执行是不是合规、判定是不是成立、真实运行时是不是留下了足够证据。

1

设计层测试

先验证设计真源、说明文档和派生产物之间有没有互相打架,确保“纸面设计”本身是完整且一致的。

2

执行层测试

再验证执行过程是不是遵守了边界、状态推进和最小证据要求,避免“看起来执行了,其实已经越界或漏证据”。

3

场景层测试

最后用一组固定场景去跑成功、失败、冲突、越界等情况,证明这套工作流在真实使用中也能稳定给出结果。

换句话说: 测试不是在问“有没有跑完”,而是在问“设计是否自洽、执行是否合规、结论是否可信、真实场景下是否稳定”。

当前实现里的设计层与执行层命令

python3 .claude/scripts/validate-workflow.py
python3 .claude/scripts/validate-workflow-spec.py --spec <workflow-spec.yaml>
python3 .claude/scripts/validate-workflow-lowlevel.py \
  --spec <workflow-spec.yaml> \
  --lowlevel <workflow-lowlevel.md>
python3 .claude/scripts/validate-run-state.py --state <RUN_ROOT>/state.json

当前实现里的场景层命令

python3 tools/runtime_smoke.py --fixture empty-project
python3 tools/runtime_smoke_matrix.py --json
当前验证能证明什么? 它已经能严格证明控制面约束和最终证据是否满足定义;它不是宿主内部每一步工具调用的全程探针,但已经不是“只看成功失败”的浅层测试。

第十步:建立长期记忆

S6 不是附录,它让 workflow 真正能进化

不会学习的 workflow 只有执行,没有演进。 S6 的核心价值是:把一次运行中积累的经验,变成下一轮运行的输入。

短期记录

lessons.md 是追加式日志。每次运行的失败经验、冲突和待提炼约束都写在这里,只追加不读取(或只读最新几条)。超过 10 条就归档。

单次运行增量

s6-lessons-delta.md 把这次运行的 run_idfailure_kind 和约束候选收成独立增量。它由 validate-lessons-delta.py 校验。

长期规则

.claude/rules/constraints.mdALWAYS/NEVER 固化稳定经验。新会话只加载这个文件,不加载完整 lessons 日志,避免上下文膨胀。

WorkflowProgram 自己也在用这套模型: 维护自己的 lessons.mdconstraints.md,用设计真源和能力矩阵避免实现漂移。它不是"只要求别人做闭环"。

第十一步:认清仓库结构

你应该把哪些目录当真源,哪些目录当派生产物

.claude/commands/源码层命令入口
.claude/skills/源码层 skills 与模板
.claude/scripts/确定性脚本链与校验器
dist/plugin/构建后的运行时载荷
tests/fixtures、expectations、transcripts
docs/HighLevel、LowLevel、教程和状态索引
维护原则: 优先修改真源文件,例如 .claude/scripts/.claude/skills/、设计文档;dist/plugin/、PPT、报告和 view/lowlevel 都应从真源重建,不建议长期手工维护。

第十二步:落地到你的项目

想为自己的项目设计 workflow?先回答这 6 个问题

不要先写 SKILL.md。先把产品边界想清楚。下面这 6 个问题, 每一个都对应着 WorkflowProgram 四层设计中的某一层。

1. 最终要交付哪些 .claude/ 文件?
2. 机器可读真源是什么?(相当于你的 workflow-spec.yaml
3. 哪些步骤必须沉到确定性脚本?(不能只靠 prompt)
4. 写入边界和冲突处理怎么定义?(怎么做 managed apply)
5. 最终 verdict 由谁给出?(runner 还是独立 judge)
6. 失败经验如何进入下一轮约束?(lessons → constraints)
最小可行版本: 一个机器可读 spec + 一个最小 entry wrapper + 一个边界明确的写入流程 + 一个独立 verdict 产物 + 一个 lessons 文件。这已经比大多数"纯 prompt workflow"稳很多了。

快速上手

5 分钟从安装到第一次运行

1

安装

需要 Python 3.10+ 和 pyyaml

git clone https://github.com/Logic-70/WorkflowProgram-CN
cd WorkflowProgram-CN
pip install pyyaml
python tools/build_plugin.py
2

启动

在你的目标项目目录中:

cd your-project
claude --plugin-dir /path/to/WorkflowProgram-CN/dist/plugin
3

用自然语言描述需求

workflowprogram-orchestrate 会自动路由到正确的入口:

"为当前项目设计一个 code review workflow"
"审计当前项目的 workflow 结构"
"验证当前项目的 workflow 资产"
4

查看运行结果

运行结束后,在你的项目中查看:

.workflowprogram/runs/<run-id>/
  state.json          # 控制面状态
  events.jsonl        # 事件流
  validation-runtime-report.md

深入阅读

想看完整版?直接跳到 Markdown 章节