跳转至

17 · Routines、Pipelines 与自动化

RoutineCron / TriggerPipeline CaseLease / VersionAutomation Ledger

一句话结论: Routine 把可重复工作模板化并在触发时创建可审计的 Issue/Run;Pipeline 则把业务对象建成带阶段、版本、租约、blocker、review gate 和自动化 ledger 的独立状态机,再通过 linked Issue 借用 Agent 执行能力。

1. 为什么 Routine 不应只是 Cron + Prompt

简单 cron callback 缺少:

  • 哪个 Company/Project/Agent 负责;
  • 使用哪个版本的说明;
  • 本次输入变量和 secret refs;
  • 是否已经触发过;
  • 创建了哪个 Issue/Run;
  • 失败怎样重试;
  • 是否可在 UI 审计/手动运行。

Routine 把这些事实持久化,而 cron 只负责“时间到了”。

2. Routine 模型

Routine 通常包含:

  • company/project;
  • title/description/status;
  • assignee Agent;
  • issue template/status/priority/work mode;
  • schedule/trigger;
  • variables/env/secret refs;
  • execution workspace preference;
  • current revision;
  • plugin management provenance。

另有 trigger、run、revision、document 等相关对象。

3. 触发类型

除了 cron,Routine 还可被手动、webhook、pipeline 或系统事件触发。Trigger 保存:

  • kind/config;
  • enabled;
  • secret/rotation(对 webhook);
  • last/next fire;
  • idempotency/source metadata。

Cron parser/formatter 独立,使 UI 显示与 Server 计划一致。

4. Routine 执行路径

sequenceDiagram
  participant T as Timer / Webhook / Manual
  participant R as Routine Service
  participant DB as PostgreSQL
  participant I as Issue Service
  participant H as Heartbeat

  T->>R: trigger(routine, input, idempotency)
  R->>DB: load active routine + revision snapshot
  R->>R: resolve variables / env refs / workspace policy
  R->>I: create origin=routine_execution Issue
  I->>DB: unique origin fingerprint prevents duplicate
  R->>DB: persist routine run / linked issue
  R->>H: assignment/automation wakeup
  H-->>R: queued/coalesced/skipped evidence

真正工作仍作为 Issue + Heartbeat 执行,所以 checkout、预算、权限、workspace 和 recovery 不会被 cron 绕过。

5. Revision Snapshot

Routine 被编辑后,历史运行必须知道使用的是哪版模板。Revision snapshot 保存当时的:

-标题/描述; - assignee/config; - variables/env; - workspace/execution options; - schedule/automation contract。

Run 绑定 snapshot,而不是事后读取“当前 Routine”。这对复现失败和 pipeline retry 很重要。

6. Variables 与 Secret

Routine variables 有类型和默认/required 规则,触发输入需要校验。Secret 使用 ref,不应作为变量明文写进 revision 或 run context。

解析顺序通常是:

definition defaults
  < routine persisted values
  < trigger/run input
  < pipeline-derived case values

覆盖仍受 schema/type 限制,不能通过输入添加任意 env key。

7. Pipeline 不是 Issue 看板列

Pipeline 处理“业务对象在流程阶段中流转”,例如内容生产、候选评审、发布流程。核心对象:

  • Pipeline;
  • Stage;
  • Transition;
  • Case;
  • Case Event;
  • Case Blocker;
  • Case ↔ Issue Link;
  • Automation Execution;
  • Case/Pipeline Document。

Issue 表达工作,Case 表达被流程管理的业务项。一个 Case 可链接多个 Issue,不能把两者合并。

8. Pipeline 定义

Pipeline 包含有序 stages 和允许 transitions。Stage 可有:

  • kind(普通、review、terminal 等);
  • enabled;
  • form/required fields;
  • transition gate;
  • approver/reviewer;
  • child breakdown/rollup;
  • automation routine;
  • workspace/issue template;
  • variables。

Transition 显式保存 from/to,不允许 UI 随便把 Case 拖到任意阶段。

9. Case 的并发字段

pipeline_cases 重要字段:

  • stageId、caseKey、fields/summary;
  • version;
  • parent case/version;
  • request key/automation attempt;
  • pending suggestion;
  • lease owner type/user/agent、token、expiry;
  • terminal kind/time;
  • retired/hidden;
  • child/terminal child count。

Version 处理 optimistic concurrency,lease 处理“谁正在编辑/推进”,两者职责不同。

10. Case Lease

stateDiagram-v2
  [*] --> Free
  Free --> Leased: user/agent acquire token
  Leased --> Leased: owner mutation + refresh
  Leased --> Free: release
  Leased --> Expired: expiresAt passed
  Expired --> Leased: next actor acquires

Mutation 要同时验证 actor ownership、lease token 和未过期。Expired lease 可被安全接管,但旧 owner 的晚到请求因 token/version 不匹配而失败。

11. Case Version

每次内容/阶段 mutation 增加 version。Client 提交 expected version:

UPDATE pipeline_cases
SET ..., version = version + 1
WHERE id = :id AND version = :expected
RETURNING *;

0 行表示有人先改了 Case,调用方必须 reload/merge,而不是覆盖。

Lease 保护临时所有权,version 保护跨请求的内容事实。

12. Transition Gate

进入目标 stage 前可能检查:

  • transition 存在且 stage enabled;
  • actor 有权限/lease;
  • required fields 完整;
  • blockers resolved;
  • child rollup 满足;
  • review approval 仍对应当前 version;
  • pending suggestion 已处理;
  • automation/retry state允许。
flowchart LR
  FROM["Current Stage"] --> EDGE{"transition exists"}
  EDGE --> FORM{"required fields"}
  FORM --> BLOCK{"blockers"}
  BLOCK --> CHILD{"children gate"}
  CHILD --> REVIEW{"review / approval current"}
  REVIEW --> CAS["versioned transition transaction"]
  CAS --> TO["Target Stage + event"]

Review approval 绑定 Case version;内容变更后旧批准不能继续授权离开阶段。

13. Case Event 是流程账本

每次 add/update/transition/review/blocker/automation 都写 Case Event,包含 actor、payload、from/to、run 等。当前 Case row 是读模型,Event 解释历史。

它不是完全 event-sourced 重放架构:权威当前状态仍在 Case row;Event 用于审计、automation trigger 和 UI timeline。

14. Blocker 与子 Case

Case blocker 是独立 DAG,并有 no-self check/unique constraint。子 Case 用 parentCaseId + parent version 表达 breakdown。

Parent 保存 child count/terminal child count 以加速 rollup,但服务仍有 reconcile/验证路径,防计数漂移导致错误过 gate。

Breakdown stage 可以从一个 Case 创建多个子 Case,并定义 carry-over field policy,避免把敏感/不相关字段全部复制。

Link role 包括:

  • origin;
  • conversation;
  • work;
  • automation。

为什么要 role?同一个 Case 可能:

  • 由某 Issue 发起;
  • 用另一 Issue 作为持续对话;
  • 为当前 stage 创建工作 Issue;
  • 自动化运行再创建执行 Issue。

服务选择“当前 conversation source”时要按 role、retired 状态和 run context 解析,不能只取最新 link。

16. Stage Automation

Stage 可绑定 Routine。进入 stage 后,系统:

  1. 固化 Routine revision;
  2. 从 Case fields 构造变量;
  3. 生成 context markdown/preamble;
  4. 创建 execution Issue;
  5. 保存 Case↔Issue automation link;
  6. 入队 Agent;
  7. 结果通过事件/回调更新 Case。

Pipeline 不直接调用模型,它复用 Routine + Issue + Heartbeat 执行栈。

17. Automation Ledger 与幂等

pipeline_automation_executions 用:

(caseId, automationId, triggeringEventId)

唯一标识一次 stage automation。它保存 routine、execution issue、status、retry-of、generation、error。

flowchart TD
  EVT["Case event"] --> INS{"insert automation ledger"}
  INS -->|unique conflict| OLD["already handled → idempotent"]
  INS -->|created| RUN["create linked Issue + run"]
  RUN --> OK{"outcome"}
  OK -->|success| DONE["ledger succeeded"]
  OK -->|failure| FAIL["ledger failed + retry plan"]
  FAIL --> RETRY["new generation / retryOf"]

先写 ledger 再启动外部工作,可防事件重复交付创建多个 Agent 任务。

18. Retry 需要清理上一次影响

Pipeline automation retry 不能简单再跑:上次可能已创建子 Case、Issue link、文档或 pending suggestion。Service 会构造 retry plan:

  • 哪些上次产物 retire;
  • 哪些保留为证据;
  • 新 generation;
  • link/child/field 怎样重建;
  • blocker/approval 是否需重新评估。

这是业务自动化比普通函数 retry 更复杂的地方。

19. Parent Rollup 与自动推进

当子 Case terminal:

  • 更新 parent counts;
  • 写 child terminal event;
  • 检查期望子数量;
  • 检查 blockers/review;
  • 满足 gate 时可 auto-advance parent;
  • 通知 linked work Issue 上游内容变化。

Rollup 仍使用 transaction/version,防多个子项同时完成让 parent 重复 transition。

20. Routine 与 Pipeline 的边界

需求 用 Routine 用 Pipeline
每周生成报告 ✓ 可能不需要
定时唤醒 Agent 做一项工作 ✓
一个业务项跨多阶段流转 ✓
每阶段有 form/review/blocker ✓
阶段进入时自动运行 Agent Pipeline 调用 Routine ✓
只需 Issue 状态流 Issue workflow 不要过度建 Pipeline

21. 可复用经验

  1. Cron 只负责触发,Routine 要保存 revision、input、Issue 和 run 证据。
  2. 自动化工作仍走正常 Issue/Heartbeat,避免治理旁路。
  3. Pipeline Case 与工作 Issue 分开,通过带 role 的 link 协作。
  4. Lease 管临时 owner,version 管 optimistic concurrency。
  5. Review approval 要绑定内容 version,变更后自动失效。
  6. 先写 automation ledger,再产生外部副作用;唯一键对齐业务事件身份。
  7. Retry 要显式清理/retire 上一 generation 的业务影响。

源码入口

  • packages/db/src/schema/routines.ts
  • server/src/services/routines.ts
  • server/src/routes/routines.ts
  • packages/db/src/schema/pipelines.ts
  • packages/db/src/schema/pipeline_cases.ts
  • packages/db/src/schema/pipeline_case_events.ts
  • server/src/services/pipelines.ts
  • server/src/services/pipeline-case-outputs.ts
  • docs/pipelines-tutorial.md

自动化最终仍需给人可审查的结果:18 · Documents、Artifacts 与 Work Products。