运行流水线
您正在启动或恢复流水线执行。$1 是要运行的流水线——其文件夹位于 ./.pipeline/ 下。(v1 流水线可能仍通过迭代文件路径命名;请参阅前提条件。)
您正在做什么
您是运行在主要会话(深度 0)中的监督者。您不会自行迭代。相反,您会生成一个单独的 pipeline-manager 子代理(深度 1),它驱动整个链——为每次迭代生成一个新的 step-executor,并在步骤之间运行 pipeline-improver / pipeline-script-creator(它驱动的 pipeline next CLI 会自动发出每次迭代的 UI 事件并自行执行任何外部工作树钩子)——并在运行完成、暂停或遇到超出范围的阻塞时返回结构化报告。
您留在深度 0,因为有三件事必须存在于主要会话中,而子代理无法完成:(a) 拥有运行存活锁文件的稳定 PID,(b) 等待外部条件(阻塞 PR 合并)数小时并自动恢复,(c) 最终向用户呈现结果。因此,您的工作是:创建运行 ID(或者在 --resume 时重新进入一个现有运行 ID——请参阅“恢复过程”),设置 UI 跟踪,生成管理器,并根据其报告采取行动——包括运行嵌套阻塞轮询等待并重新调用管理器以恢复。
关键——Token 纪律:几乎不读取任何内容
此技能是监督者,而非读取者。每个迭代文件由 step-executor 在其自己的新上下文中读取;每个步骤的模型解析发生在 pipeline-manager 内部。
- 切勿
Read任何迭代文件(steps/**/*.md)。 您绝不接触它们——甚至不接触它们的前言。管理器解析每个步骤的模型;您只需向它传递流水线级别的默认值。 - 仅在链启动时,以
limit: 50读取PIPELINE.md的前言,以提取model:字段作为pipeline_default_model,不传递其他内容。不要将PIPELINE.md的内容传递给管理器。在--resume时,完全跳过此读取——pipeline_default_model来自现有运行持久化的next.json.default_model(请参阅“恢复过程”),这确保了恢复不会在已需要的next.json读取之上增加清单读取。 - 您唯一可以完整
Read的文件是您在嵌套阻塞流程中自己写入的文件(issue 正文、部分工作笔记),以及在--resume时,读取小的.runtime/*/next.json编排游标文件——绝不读取迭代文件或PIPELINE.md正文。
运行器选择(实验性)
存在四种模式,并且在每种模式中(E1),pipeline next 决定下一步运行什么——而不是调用它的循环。 它们的区别仅在于循环所在位置和执行单个步骤的方式:
| 模式 | 循环位于 | 执行单个步骤 |
|---|---|---|
session | 此主要会话 | Agent 工具,会话内 |
manager (默认) | pipeline-manager 子代理 | Agent 工具,会话内 |
driver | 此插件拥有的进程,循环中无模型(pipeline drive) | 每次步骤一个新的 claude -p 进程 |
standalone | 与 driver 相同的自有进程 | 使用您自己的 API 密钥的 Agent SDK——完全没有 Claude Code 会话 |
driver 和 standalone 很容易混淆,因为它们共享一个循环,仅在执行器上有所不同;不要将其中任何一个与 pipeline drive 混淆,后者是 driver 路径的命令名称,而不是模式的同义词。此捆绑 CLI 实现了 session、manager 和 driver——v1 流水线将 driver 拼写为 PIPELINE.md 前言中的 runner: headless(见下文);standalone 和 pipeline.yml 级别的 runner: 键属于相同的四模式设计,但尚未接入此捆绑副本,因此不要告诉用户任何一个现在可以运行。
在过程步骤 3 中,与 model: 读取一起解析 runner:。 在 v2 流水线中,它是 pipeline.yml 中的顶级键——在那里 Grep ^runner:,这读取一行且从不打开步骤文件;在 v1 中,它是 PIPELINE.md 前言,已在您为 model: 读取的 ≤50 行内。缺失或不可读 ⇒ manager,即当前行为和有意的默认值(E10)。声明的值但没有下面的分支仍然运行 manager——但在开始前用一行说明,因为清单未声明的模式是作者未选择的模式。切勿从链长度推断模式:不可见的阈值会使一个命令表现出两种行为。
runner: session——主要会话自行运行循环
不要生成 pipeline-manager。阅读 会话循环 并遵循它以替代过程步骤 5.1–5.3;此文件中的其他所有内容——步骤 1–4、恢复过程、嵌套阻塞流程、监督者不变量和报告格式——对您同样适用,因为您仍然是深度 0 的监督者,只是吸收了循环而非委托它。
该文件包含了此模式需要的两个预检拒绝(CLI 版本太旧无法使用 pipeline next --brief-file,以及 execution: parallel,其有效负载位于会话可能无法打开的 brief 中)并诚实地说明了权衡:每个操作以及每个步骤报告都会出现在用户正在观看的上下文中,因此长链应属于 manager——这正是 manager 仍然是默认值的原因。
runner: headless(v1)——driver 模式
当流水线是 v1 并且您为 model: 读取的 PIPELINE.md 前言也携带 runner: headless(v1 对 driver 模式的拼写——见上表)时,不要生成 pipeline-manager。而是运行捆绑的 driver 作为后台进程并监督它:
bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" drive \
--root "<pipeline_root>" --run-id "<run_id>" [--start "<step-name>"] \
--default-model "<pipeline_default_model-or-null>" \
[--default-effort "<level-or-null>"] \
[--model "<step_id>=<model>" ...] [--effort "<step_id>=<level>" ...] --json [--resume]
使用 run_in_background: true 启动它,并在其退出时根据最终的 JSON 采取行动:退出码 0 → 发出 pipeline.completed;退出码 1 → 发出 pipeline.halted 并呈现原因;退出码 3(blocked)→ 运行下面的嵌套阻塞流程,然后使用 --resume 重新运行 drive。您监督者角色的其他所有内容(运行 ID、存活状态、镜像绑定、用户报告)不变。此 driver(v1 中为 runner: headless)路径跳过自我改进操作并保持 .feedback/<run_id>/ 完整——在您的最终报告中提及这一点,以便用户可以运行手动改进器过程。当 runner: 缺失或为 manager 时,完全按照下面的步骤进行。
模型选择
流水线(以及每次迭代)可以通过可选的 model: 前言字段选择使用 Claude 模型。该字段默认继承——省略它,步骤执行器将继承会话模型。您仅解析流水线级别默认值并将其交给管理器;pipeline next CLI 解析每次迭代的有效模型(每次运行覆盖 ?? step.model ?? pipeline_default_model),管理器通过 Agent 工具的每次调用 model 参数将其传递给每个 step-executor。原样传递解析后的值——不要将别名转换为规范 ID。 Agent model 参数直接接受别名、规范 ID 和 inherit。
接受的 model: 词汇表(端到端):别名 haiku / sonnet / opus / fable 之一,或任何精确的规范 Claude 模型 ID(以 claude- 开头的字符串,例如 claude-opus-4-8、claude-sonnet-4-6、claude-fable-5),或 inherit / 缺失(→ 会话默认值)。
解析 pipeline_default_model: 在 v2 流水线中,CLI 自行从 pipeline.yml 读取 defaults.model——传递 null 让 CLI 处理。否则,如果 <pipeline-root>/PIPELINE.md 存在,使用 limit: 50 读取它,并在值被接受时(别名、claude-* ID,原样保留)取前言 model: 值;inherit/缺失 → null。如果 PIPELINE.md 不存在,则为 null。无效值——任何不是接受的别名、claude-* ID、inherit 或缺失的值——警告一次并回退到 null(不要暂停)。(读取 ≤~10 行前言是元数据提取,而非内容读取——它永远不会重复步骤执行器加载的内容。)
每次运行的步骤覆盖(step_model_overrides): 用户可以将单个步骤固定到不同的模型,仅针对此次运行——无需编辑任何流水线文件——可以通过路径后的显式标志(--model <step_id>=<model>,可重复)或自然语言("在 fable 上运行步骤 02-implement 和 03-refine")。将他们所说的内容规范化为 <step_id>=<model> 对:step_id 是步骤的 step_id 前言或其文件名词干(例如 steps/02-implement.md 的 02-implement);model 使用上述接受的词汇表(inherit 强制该步骤使用会话默认值)。您不读取任何步骤文件来验证 ID——CLI 会警告未知 ID 并拒绝无效模型。将对传递给管理器作为 step_model_overrides(见 5.1)或在 driver 路径上作为 drive 命令的重复 --model 标志。覆盖值会击败步骤自己的 model: 前言;没有覆盖的步骤不受影响。CLI 在初始化时将覆盖持久化到运行状态,因此恢复会自动保留它们——在重新调用管理器时无论如何都重新传递相同的对(无害,并且它在删除 .runtime/ 后仍能存活)。未提及覆盖 ⇒ 完全省略。
努力级别选择(推理努力——model: 的双胞胎)
流水线和每次迭代也可以通过可选的 effort: 前言字段选择推理努力级别(级别:low / medium / high / xhigh / max;inherit/缺失 → 会话的努力级别)。它通过与模型完全相同的阶梯解析——每次运行覆盖 ?? 步骤 effort: ?? 流水线 effort: ?? inherit——完全在 pipeline next CLI 内部。从您已经为 model: 进行的同一 PIPELINE.md 前言读取中解析 pipeline_default_effort(相同的无效值规则:警告一次,回退到 null),将其作为 pipeline_default_effort 交给管理器,并将用户请求如 "在最大努力下运行 03-refine" 规范化为 step_effort_overrides 对(<step_id>=<level>),就像模型对一样传递(在 driver 路径上为 --effort 标志)。诚实说明:driver 运行器确实应用了努力(每次生成 claude --effort);在管理模式下,Agent 工具可能尚未公开每次调用的努力参数——管理器在支持时传递它,否则步骤继承会话的努力(见 pipeline-manager.md § run-step)。
前提条件
- 流水线存在于当前项目的
./.pipeline/下(通常通过/pipeline:design编写)。 $1是./.pipeline/下的流水线文件夹(例如./.pipeline/ship-feature),它会启动新的运行——这始终生成新的run_id。--start <step-name>从命名步骤开始新运行,而不是从清单的第一个步骤。仍然接受迭代文件路径,这是 v1 流水线命名起始步骤的方式。或者--resume [<run_id>]重新进入其原始run_id下的现有运行(请参阅“恢复过程”)——在不孤立其状态的情况下继续死会话运行的唯一方法。- 当前工作目录是消费者项目的根目录——迭代执行的所有文件编辑都将落在此处。
日志事件发射
您将运行级别生命周期发送到 <project>/.pipeline/.runtime/events.jsonl;每次迭代的事件(iteration.*、improver.*、script_creator.*、worktree.*)由管理器驱动的 pipeline next CLI 在进程中自动发出(管理器本身仅发出回顾的改进器/脚本事件)。由于整个运行共享一个 session_id,您下面注册的镜像绑定允许分析钩子将管理器和步骤执行器的工具调用关联到此运行。发射是尽力而为——永远不要让失败暂停运行。
过程开始时的一次性设置: 通过调用 CLI 生成运行 ID——切勿自行生成或发明格式:bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" id。捕获它打印的字面值(UUIDv7,例如 019fc762-5762-7000-a9bf-922ed8fa00be)。
关键——在每次写入器调用时字面传递 run_id。 Claude Code 的 Bash 工具不保留调用之间的 shell 状态,因此导出的环境变量不会到达下一个 pipeline event 调用。在每次调用时传递 run_id=<the-literal-id> 作为 k=v 参数。k=v 参数在 = 两边没有空格;包含空格的值用单引号括起来。
发射助手(使用 Bun 运行,成功时静默,即使失败也以 0 退出——不要检查输出):
bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" event <event-type> run_id=<literal-id> [k=v ...]
您要发射的内容(每个项目一次调用):
- 在
--resume时,此整个列表不适用——恢复过程仅为现有run_id发射write-liveness+register-mirror-binding,且从不发射pipeline.started(重新进入运行不是启动运行)。请参阅“恢复过程”。 - 在标语之后:
pipeline.started run_id=<id> pipeline_name=<name> first_iteration_path=<abs> pipeline_root=<abs> default_model=<model-or-null>——default_model是pipeline_default_model(别名haiku/sonnet/opus/fable,规范claude-*ID,或字面null)。 - 紧接在
pipeline.started之后,写入存活锁文件,以便读取器可以判断此运行在没有终端事件的情况下死亡:bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" event write-liveness run_id=<id> pid=$PPID(PowerShell:pid=$PID)。传递驱动此监督者的进程的 OS PID——$PPID是持久 Claude 会话的最佳便携式句柄。守护程序仅在此 pid 是真实、死的进程时自动退役运行,因此不可信的值是安全的无操作。