7 阶段流水线详解:从源码到可安装 CLI 做了什么
一条命令背后发生了什么
当你执行 /cli-anything ./gimp 的时候,Claude Code 里的 AI Agent 并不是在做一个简单的任务。它会按顺序跑完 7 个阶段,每个阶段都有明确的目标和交付物。
这 7 个阶段是 CLI-Anything 的核心方法论,定义在一个叫 HARNESS.md 的文件里。这个文件是整个项目的 SOP(标准操作流程),所有平台插件(Claude Code 插件、OpenCode 命令、Codex skill)都引用同一个 HARNESS.md,保证不同平台上生成的 CLI 质量一致。
下面逐个拆解每个阶段在做什么、关键决策是什么、以及 Blender 的源码是怎么被处理的。
阶段 1:分析(Analyze)
目标:理解目标软件的架构,找到所有可程序化的功能入口。
这个阶段要做的事情比听起来多得多。不是简单地把源码扫一遍就完事了,而是要回答三个关键问题:
- 软件用什么方式暴露功能? 直接命令行参数?IPC 通信?文件格式?Python 绑定?
- GUI 操作对应的底层调用是什么? 比如 GIMP 里点击"添加图层",背后调的是什么 API?
- 哪些功能可以脱离 GUI 独立运行? 哪些必须有人工交互?
以 GIMP 为例,分析阶段会找到三种可行的后端路径:
- GEGL 操作:GIMP 2.10+ 的现代图像处理图引擎
- Script-Fu:GIMP 内置的脚本语言
- Pillow:作为 fallback,用于生成中间图像文件
这个阶段的交付物是一份功能映射表,列出了所有可暴露的命令及其对应的底层实现方式。
阶段 2:设计(Design)
目标:把分析结果组织成合理的命令结构和数据模型。
这是我认为最有技术含量的阶段。命令结构的设计直接影响 Agent 的使用体验——太粗了不够用,太细了记不住。
设计阶段要做几件事:
命令分组。以 Blender 为例,生成的 CLI 大致按这样的逻辑分组:
blender scene # 场景管理:创建、加载、保存
blender object # 物体操作:添加、变换、材质
blender render # 渲染控制:参数设置、渲染触发
blender material # 材质系统
blender mesh # 网格数据操作
状态模型。Blender 是一个有内部状态的应用——当前场景、选中的物体、渲染设置。要不要维护这些状态?CLI-Anything 的答案是:可选。你可以在 REPL 模式下维护状态(类似操作 Blender 文件的过程),也可以每次都通过 --project 参数传递完整状态。
输出格式设计。每个命令至少有两种输出格式:人类可读的自然语言描述,以及 --json 模式下的结构化数据。JSON 模式用于 Agent 消费,自然语言模式用于调试。
阶段 3:实现(Implement)
目标:写出可运行的 Click CLI 代码。
这个阶段生成的核心文件结构大概长这样(以 GIMP 为例):
cli_anything/gimp/
├── __init__.py
├── cli.py # Click 命令入口
├── core/
│ ├── __init__.py
│ ├── project.py # 项目文件读写
│ ├── layer.py # 图层操作
│ ├── filter.py # 滤镜处理
│ └── export.py # 导出功能
├── backends/
│ ├── __init__.py
│ ├── gegl.py # GEGL 后端
│ ├── scriptfu.py # Script-Fu 后端
│ └── pillow.py # Pillow fallback
└── utils/
├── __init__.py
├── repl_skin.py # REPL 界面统一皮肤
└── validators.py # 参数校验
repl_skin.py 是统一 REPL 界面的关键。每个 CLI 都使用同一个 REPL 皮肤,有统一的 banner 样式、命令提示符、进度显示、彩色输出。这意味着 Agent 学会了用 GIMP CLI,切换到 Blender CLI 不需要重新学习界面操作。
JSON 输出的实现。在 Click 命令上装饰 @click.option('--json'),然后在 handler 里根据 flag 切换输出格式:
@click.command()
@click.option('--json', 'output_format', flag_value='json', default=True)
@click.option('--human', 'output_format', flag_value='human', default=False)
def layer_add(output_format, ...):
result = do_layer_add(...)
if output_format == 'json':
click.echo(json.dumps(result, indent=2))
else:
click.echo(f"✓ Added layer '{name}' to project")
阶段 4:规划测试(Plan Tests)
目标:制定测试策略,不要等到写完了才想起要测试。
在真正写代码之前,Agent 会先写一份 TEST.md,里面包括:
- 测试分类:哪些是单元测试(隔离验证单个函数),哪些是端到端测试(验证完整流程)
- 边界条件:非法参数、超大文件、缺失后端时会发生什么
- 预期行为:通过的标准是什么
这份文档既是测试计划,也是验收标准。后面的测试结果会更新到这个文件里,形成可追溯的测试历史。
阶段 5:编写测试(Write Tests)
目标:实际写出测试代码。
测试分四层,这个设计挺有意思的:
第一层:单元测试。用合成数据测试核心函数,不依赖任何外部软件。比如测试 layer_add() 函数的参数校验、返回值格式。Blender CLI 的单元测试有 150 个。
第二层:端到端测试(原生)。验证生成的中间文件格式正确。比如 LibreOffice 生成的是 ODF ZIP 包,测试会解压它,检查内部 XML 结构是否合法;Blender 导出的是 .blend 文件,测试会检查文件魔数。
第三层:端到端测试(真实后端)。这是最严格的一层——必须真正调用软件并验证输出。Blender 的测试会真的运行 blender --background 来渲染一个场景,然后检查输出的 PNG 文件里是否包含 %PDF 之外的正确图像数据。如果 Blender 没有安装,这层测试会直接失败,而不是跳过。
第四层:CLI 子进程测试。通过 subprocess.run() 调用安装后的命令,验证 CLI 安装包本身没有错误。
为什么坚持第三层? 项目作者的原话是:"后端缺失时测试直接失败(而非跳过),确保功能的真实性。"这是和其他玩具级 CLI 生成工具最大的区别——不给你虚假的通过率。
阶段 6:记录结果(Document)
目标:把测试结果写回 TEST.md,形成可追溯的文档。
这一阶段容易被忽视,但对维护很有用。每次运行 cli-anything:test 或者 cli-anything:validate,结果都会追加到 TEST.md 里。一段时间之后,打开这个文件就能看到:这个 CLI 经历了多少次迭代、哪些边界情况曾经失败过、修复了哪些 bug。
阶段 7:发布(Publish)
目标:把生成的 CLI 变成可安装的 Python 包。
核心是生成 setup.py:
from setuptools import setup, find_packages
setup(
name=f"cli-anything-{software_name}",
version="1.0.0",
packages=find_packages(),
install_requires=[
'click>=8.0',
# 其他依赖
],
entry_points={
'console_scripts': [
f'cli-anything-{software_name}=cli_anything.{software_name}.cli:main',
],
},
package_data={
f'cli_anything.{software_name}': ['skills/SKILL.md'],
},
)
entry_points 是关键——它告诉 setuptools 创建一个全局可执行的命令脚本。安装之后,cli-anything-gimp 就在 PATH 里了,任何进程都能找到它。
package_data 把 SKILL.md 打包进 Python 包,Agent 通过 pip 安装之后,REPL banner 会显示 SKILL.md 的绝对路径,AI 工具可以直接读取它来做下一步决策。
refine:增量的秘密
7 阶段构建完成之后,你可能会发现某些功能没有覆盖到。refine 命令就是来解决这个问题的。
refine 的工作方式很有意思:它不会重建,而是对比当前 CLI 的功能清单和软件实际拥有的能力,找出缺口,然后只对缺口进行实现。
/cli-anything:refine ./gimp "更多滤镜和批处理相关的命令"
每次 refine 都是增量的——已有的命令不会被改动,新命令会被添加到对应的模块里,测试也会相应扩展。这就像给一个房子做装修,不需要推到重来,可以一个房间一个房间来。
总结:流水线为什么这样设计
回头看这 7 个阶段,有一条主线贯穿始终:
设计先行,实现其次,测试贯穿,文档归档。
不是让 Agent 随便写代码然后跑测试碰运气,而是先把要做什么设计清楚,再用测试来验证这个设计是否被正确实现。这个思路其实和人工写代码的最佳实践是一致的——只不过 CLI-Anything 把这个流程自动化了。

浙公网安备 33010602011771号