Hotdry.
ai-systems

Cook CLI 子进程编排与流式输出捕获的工程实现

深入解析 Cook CLI 如何通过 Node.js child_process 实现 Claude Code 子进程编排、流式输出捕获与多 agent 并发调度的工程细节。

在 Claude Code 生态中,如何高效编排多个 AI Agent 协同工作一直是工程实践的核心挑战。Cook CLI 作为一款新兴的任务编排工具,通过简洁的 DSL 语法实现了「工作 - 审查 - 门控」的迭代循环,并在并行执行场景下利用 Git Worktree 实现进程隔离。本文将从子进程管理、流式输出捕获、并发调度三个维度,深度解析 Cook CLI 的工程实现细节。

子进程编排架构

Cook CLI 本质上是一个 Node.js 编写的 Supervisor 进程,它并不直接执行代码修改,而是作为调度层调用 Claude Code、Codex 或 OpenCode 等底层 Agent。其核心运行机制围绕三个原语展开:Work(工作单元)、Loop Operators(循环算子)和 Composition Operators(组合算子)。

当用户在终端输入 cook "Implement dark mode" review 时,Cook 解析命令后首先创建或复用一个 Git Worktree(用于版本隔离),随后通过 child_process.spawn 启动目标 Agent 进程。值得注意的是,Cook 默认使用「Agent」沙箱模式,即让 Agent 利用自身的 OS 级别沙箱能力,而无需启动 Docker 容器,这大大降低了资源开销。对于需要更强隔离的场景,可通过 --sandbox docker 参数切换到 Docker 模式。

在进程启动层面,Cook 内部维护了一个任务队列和状态机。每个 Work 单元对应一次 Agent 调用,循环算子(如 x3 表示重复三次)则控制状态机的跳转逻辑。审查阶段(review)会启动第二个 Agent 实例作为 Reviewer,第一个 Agent 的输出作为 Reviewer 的输入,这种设计实现了工作节点与审查节点的职责分离。

流式输出捕获的实现

流式输出是 CLI 工具交互体验的关键。Cook 在捕获子进程 stdout/stderr 时采用了 Node.js 的标准流模式,通过 child.stdout.on('data', callback) 实现实时输出转发。当 Agent 产生 Thinking 过程或工具调用结果时,这些文本会即时打印到终端,让用户能够观察 Agent 的推理进展。

从代码层面看,典型的流式捕获模式如下:Cook 使用 spawn 创建子进程并设置 stdio: ['ignore', 'pipe', 'pipe'],从而获得对 stdout 和 stderr 的管道控制权。在监听 data 事件时,通过 process.stdout.write(chunk) 将内容直接转发到父进程,实现所见即所得的终端体验。同时,Cook 还会将完整输出累积到缓冲区,供后续的审查阶段使用。

对于需要更高精度控制的场景(例如提取结构化日志),Cook 支持自定义解析规则。用户可以在 prompts 中要求 Agent 输出特定格式的日志(如 STEP: {step: "read", status: "done"}),然后通过正则表达式解析这些行,实现对 Agent 内部状态的监控。这种设计在需要将 Agent 进度对接外部监控系统时尤为有用。

多 Agent 并发调度与 Git Worktree 隔离

并行执行是 Cook 最具特色的能力之一。当用户使用 v3(或 race 3)算子时,Cook 会在不同的 Git Worktree 中同时启动多个 Agent 实例,每个实例拥有独立的代码目录视图,从而避免并发修改导致的冲突。这种设计巧妙利用了 Git 的原子性分支切换能力,实现了接近原生的并行隔离。

调度层面的实现逻辑如下:当解析到 vN 算子时,Cook 首先在当前仓库中创建 N 个独立的 Worktree 分支(如 cook/run-1cook/run-2 等)。随后,使用 Promise.all 并行启动 N 个子进程,每个子进程在各自的 Worktree 中执行相同的任务。执行完成后,Cook 收集所有结果并交由 Resolver(如 pickmerge)进行裁决。

pick 解析器会根据用户指定的评判标准(如「least code」或「cleanest result」)选择最佳结果,并将其合并回主分支。merge 解析器则更为激进,它会尝试将多个结果进行智能合成,生成一个取长补短的新实现。compare 解析器则仅输出对比文档,不执行合并,适合需要人工决策的场景。

这种基于 Worktree 的并发模型相比传统的进程池方案具有明显优势:它天然支持代码级别的隔离,不同分支的修改互不影响;同时依托 Git 的版本控制能力,失败的任务可以轻松回滚。此外,Cook 还支持通过 --work-agent--review-agent 参数为不同阶段指定不同的模型,实现了异构 Agent 的混合编排。

交互设计与门控机制

除了技术实现,Cook 的交互设计同样值得深入探讨。其核心设计哲学是将复杂的 Agent 编排抽象为直观的命令行语法,让开发者以声明式的方式定义工作流。review 算子是这种设计思路的典型体现:它自动嵌入了一个审查 - 门控循环,审查者检查工作质量后,门控决定是「DONE」还是「ITERATE」。

门控逻辑通过自然语言 prompt 实现,这是 Cook 与传统 CI/CD 流程的本质区别。开发者可以编写自定义的门控规则,如「DONE if WCAG AA compliant, else ITERATE」,Agent 会根据实际输出判断是否满足条件。这种设计将质量标准从配置层面提升到语义层面,使得非技术人员也能理解并调整验收规则。

在实际工程中,Cook 的典型应用场景包括:大规模代码重构(通过 xN 迭代改进)、多方案选型(通过 vs 对比不同实现)、长任务分解(通过 ralph 驱动任务列表演进)。每个场景都对应着特定的工作流组合,而 Cook 的算子系统提供了足够的灵活性来适配这些需求。

工程落地的关键参数

基于上述分析,以下是 Cook CLI 实际使用中的关键参数清单:安装方式为 npm install -g @let-it-cook/cli;初始化项目配置使用 cook init,它会生成 COOK.md.cook/config.json.cook/Dockerfile;沙箱模式通过 --sandbox agent(默认)或 --sandbox docker 指定;模型选择通过 --work-agent claude --work-model opus 这样的参数对进行细粒度控制;最大迭代次数直接在算子后添加数字,如 review 5 表示最多迭代五次。

对于需要持续监控的生产场景,建议在 prompts 中嵌入结构化日志输出格式,便于后续对接 Prometheus 或 Grafana 等监控系统。并行任务的资源占用也需要关注,每个 Worktree 会独立占用一个 Agent 实例,合理控制 vN 中的 N 值可以避免资源耗尽。

小结

Cook CLI 通过子进程编排、流式输出捕获和 Git Worktree 隔离三大技术支柱,实现了一套简洁而强大的 Agent 编排方案。其设计思路将复杂的并发控制和状态管理封装为直观的算子语法,让开发者能够聚焦于业务逻辑而非基础设施细节。随着 Claude Code 生态的持续演进,类似 Cook 这样的编排工具将成为连接单点 Agent 与复杂软件工程的桥梁。


参考资料

查看归档