Claude Code Dynamic Workflow:一个可恢复的多 Agent Harness Runtime

从模型可见接口、受限 JS VM、scheduler、resume journal、progress projection 到 failure semantics,拆解 Claude Code Dynamic Workflow 的整体设计。

这篇文章面向 agent / harness 工程师,重点放在 Dynamic Workflow 的执行模型、状态边界和可借鉴的 runtime 设计。以下分析基于本机安装的 Claude Code 2.1.193 行为观察。

Executive Summary

  • Dynamic Workflow 可以理解成 Claude Code 内置的 deterministic multi-agent harness runtime。
  • 主 Claude 负责生成、选择或修改 workflow script;runtime 负责执行脚本、调度 subagents、记录进度和恢复状态。
  • 模型可见入口是 Workflow / RunWorkflow,输入包括 scriptnameargsscriptPathresumeFromRunId
  • workflow script 运行在受限 JavaScript VM 中,runtime 注入 agent()parallel()pipeline()workflow()budgetphase()log()args
  • scriptPath 把一次性 tool call 变成可编辑 artifact;Claude 可以直接 Edit / Write 这个脚本,再用同一路径重跑。
  • resumeFromRunId 依赖 journal 和 agent-call chain key。缓存 key 大致是 sha256(prevKey + prompt + canonical(optsSubset)),控制流变化会自然影响后续复用。
  • pipeline() 是默认推荐 primitive,语义是 item-level streaming;parallel() 是 barrier,只有需要全量上游结果时才适合。
  • progress 来自 runtime 对 workflow_phaseworkflow_agentworkflow_log 的 task projection,不能解读成模型内部“思考百分比”。
  • 安全边界来自 concurrency cap、agent lifetime cap、array boundary cap、token budget hard ceiling、stall retry、structured output retry、abort / skip / retry 控制。
  • Agent Team 更像交互式协作 surface;Dynamic Workflow 更像可保存、可恢复、可观察的 orchestration program。

Mental Model

Dynamic Workflow 至少有三层:

  1. Model-visible layer:主 Claude 能看到 Workflow 工具,以及 workflow 的输入输出 contract。
  2. Execution layer:受限 JS VM 执行 workflow script,并通过 host hooks 调用 subagent runtime。
  3. Projection layer:runtime 把 phase、agent、log 投影到 local workflow task,UI 再展示 /workflows、后台任务、进度条和控制按钮。
flowchart TD User["User request"] --> Main["Main Claude"] Main --> Tool["Workflow / RunWorkflow tool"] Tool --> Script["Workflow script"] Script --> VM["Restricted JavaScript VM"] VM --> Hooks["Host hooks"] Hooks --> Agents["Subagent runtime"] Hooks --> Task["LocalWorkflowTask"] Agents --> Journal["journal.jsonl + transcripts"] Task --> UI["/workflows + background task UI"] Journal --> Resume["resumeFromRunId"] Resume --> Tool

这个三层模型很重要。workflow script 承载 deterministic control plane;文件系统、网络、进程、MCP 等实际能力来自 agent() 背后的 subagent main loop、工具系统、权限系统、MCP 连接和 task registry。

Workflow Tool Contract

模型能调用的是一个 workflow tool。用户侧通常看到 Workflow,内部别名里也有 RunWorkflow。核心输入如下:

字段含义
script自包含 workflow script。必须以 export const meta = ... 开头。
name运行一个已注册 workflow,可以来自内置、项目 .claude/workflows/ 或 plugin。
args原样暴露给脚本的全局变量。应该传 JSON 值,避免把数组/对象先 stringify。
scriptPath从磁盘读取 workflow script。优先级高于 scriptname
resumeFromRunId从同一 session 内的既有 workflow run 恢复。

输出里通常包含:

字段含义
statusasync_launchedremote_launched
taskId本地 task registry 中的 workflow task id。
taskType本地 workflow 是 local_workflow,远端场景可表现为 remote_agent
runId本地 workflow run id,形如 wf_...,用于 resume。
scriptPath本次持久化后的脚本路径。后续迭代直接改这个文件。
transcriptDirsubagent transcript 输出目录。
sessionUrl远端 cloud session URL,仅远端场景有。
warning非阻断提醒,例如远端会基于已 push 分支运行。
error语法检查或输入校验失败时的错误。

scriptPath 的存在改变了 workflow 的生命周期。普通 tool call 的输入会淹没在对话上下文里;workflow script 会落盘,成为可编辑、可审查、可再次执行的 artifact。

flowchart LR Inline["Workflow({ script })"] --> Persist["persist scriptPath"] Persist --> Edit["Edit / Write script file"] Edit --> Rerun["Workflow({ scriptPath })"] Rerun --> Resume["Workflow({ scriptPath, resumeFromRunId })"]

Script Contract And Registry

每个 workflow script 都要先声明 meta

export const meta = {
  name: "review-changes",
  description: "Review changed files across multiple independent dimensions.",
  whenToUse: "Use for high-recall review of a change set.",
  phases: [
    { title: "Scope", detail: "Pin diff and review surface" },
    { title: "Find", detail: "Run independent finder angles" },
    { title: "Verify", detail: "Adversarially verify candidates" },
    { title: "Synthesize", detail: "Merge, rank, and cap findings" },
  ],
}

// Script body starts here.

meta 的约束比普通配置更严格:

  • export const meta = ... 必须是脚本第一条语句。
  • meta 必须是 pure literal。
  • 不能引用变量、函数调用、spread、computed key、template interpolation。
  • meta.namemeta.description 是必填非空字符串。
  • phases 用于 UI 预注册阶段;脚本里 phase("...")agent(..., { phase }) 会投影到对应 group。

workflow registry 有几类来源:

  • Built-in workflows:当前版本能看到 code-reviewdeep-research 这类内置 workflow。
  • Project workflows:项目内 .claude/workflows/*.js
  • User workflows:用户级 workflow 目录。
  • Plugin workflows:plugin manifest 可声明 workflowsPathworkflowsPaths

脚本有大小上限,当前观察到的 cap 是 512 KiB。这避免把 workflow 变成无限制代码包,也让 tool input、落盘、parse、approval dialog 的成本保持可控。

Restricted JavaScript VM

workflow script 使用 JavaScript 语法。TypeScript 类型注解、interface、generic 都会 parse 失败。

VM 内可用的关键全局对象:

名称作用
agent(prompt, opts)启动 subagent,并把 subagent final response 作为返回值。
parallel(thunks)并发执行一组 thunk,等待全部 settled 后返回数组。
pipeline(items, ...stages)让每个 item 独立流过多个 stage,没有 stage 间全局 barrier。
workflow(nameOrRef, args)在当前 workflow 内调用一个子 workflow。
phase(title)设置当前阶段,影响后续 agent 的 UI 分组。
log(message)写入 workflow log。
budget暴露 token target、已花费、剩余量。
argstool input 传入的参数值。
console输出被接到 workflow log。

VM 的限制来自可恢复性和 host boundary 安全:

  • 无 Node.js fschild_processimport() 这类直接宿主能力。
  • Date.now()Math.random()、无参 new Date() 不可用。
  • codeGeneration.stringscodeGeneration.wasm 关闭。
  • 跨 VM 边界传值时会 sanitize:函数被丢弃,__proto__ 被跳过,循环引用被处理。
  • 单个数组穿越边界有 cap,当前观察是 4096
  • workflow 返回值不能是 function,最终会被 clone / JSON 化为可序列化结果。

这些约束让脚本更接近 deterministic control plane。时间戳、随机性、外部状态应该通过 args 或 subagent 工具调用显式进入,避免让脚本本身隐式漂移。

Host Hook Architecture

runtime 会先 parse meta 和 script body,再创建 VM context。VM 内的函数由 host hooks 包装,调用时会跨回宿主 runtime。

flowchart TD Input["Workflow tool input"] --> Resolve["resolve script / name / scriptPath"] Resolve --> Meta["parse meta"] Meta --> Check["syntax + determinism checks"] Check --> Persist["persist script under session dir"] Persist --> VM["create restricted JS VM"] VM --> Inject["inject host hooks"] Inject --> Agent["agent()"] Inject --> Parallel["parallel()"] Inject --> Pipeline["pipeline()"] Inject --> Child["workflow()"] Agent --> Loop["subagent main loop"] Pipeline --> Agent Parallel --> Agent Child --> VM2["child workflow VM"] Loop --> Result["string / structured object"] Result --> VM

agent() 的返回值会回到脚本。子 Agent 被提示:它的 final text 会作为函数返回值,而非给人看的聊天回复。这个提示很关键,否则 subagent 容易输出 “Done” 或一段面向用户的解释,导致 workflow 难以 parse。

有 schema 时,runtime 会给 subagent 加 StructuredOutput 工具要求。subagent 必须通过工具调用返回结构化对象,validation 失败会触发重试。

Orchestration Primitives

agent(prompt, opts)

agent() 是 workflow 的基本执行单元。

const result = await agent("Review this diff for correctness bugs.", {
  label: "correctness",
  phase: "Find",
  schema: FINDINGS_SCHEMA,
  effort: "high",
})

常见 opts:

选项影响
labelUI 展示用 label,不进入 resume key。
phaseUI 分组用 phase,不进入 resume key。
schema要求 StructuredOutput,进入 resume key。
model覆盖本次 subagent model,进入 resume key。
effort覆盖 reasoning effort,进入 resume key。
isolation例如 worktree,进入 resume key。
agentType使用自定义 agent definition,进入 resume key。
stallMsstall detection 超时,不进入 resume key。

无 schema 时,agent() 返回 final text string。有 schema 时,返回 validated object。用户 skip、某些终局 API error 或 pipeline/parallel 分支失败时,结果可能是 null,脚本应显式过滤。

parallel(thunks)

parallel() 接收 thunk 数组,直接传 promise 数组会失败:

const results = await parallel([
  () => agent("Find correctness bugs.", { label: "correctness", schema: FINDINGS }),
  () => agent("Find test gaps.", { label: "tests", schema: FINDINGS }),
  () => agent("Find compatibility risks.", { label: "compat", schema: FINDINGS }),
])

const findings = results.filter(Boolean).flatMap((r) => r.findings)

它是 barrier。所有 thunk settle 后,调用才返回。某个 slot throw 时,通常会被记录成 workflow_log,对应结果为 null。这种语义适合“下一步必须看到完整上游集合”的场景,例如 dedupe、全量排序、全局 early exit。

pipeline(items, ...stages)

pipeline() 是 Dynamic Workflow 里更值得注意的 primitive。

const verified = await pipeline(
  DIMENSIONS,
  (dimension) =>
    agent(dimension.prompt, {
      label: `find:${dimension.key}`,
      phase: "Find",
      schema: FINDINGS_SCHEMA,
    }),
  (review, originalDimension, index) =>
    parallel(
      review.findings.map((finding) => () =>
        agent(verifyPrompt(finding), {
          label: `verify:${index}:${finding.file}`,
          phase: "Verify",
          schema: VERDICT_SCHEMA,
        })
      )
    )
)

pipeline() 没有阶段间全局 barrier。item A 的 stage 1 完成后可以立即进入 stage 2;item B 可能仍在 stage 1。对 code review、research、audit 来说,这比“先 parallel 全部 finder,再 parallel 全部 verifier”的 wall-clock 更好。

gantt title pipeline 没有全局阶段 barrier dateFormat X axisFormat %s section Item A Find A :a1, 0, 2 Verify A :a2, 2, 4 section Item B Find B :b1, 0, 5 Verify B :b2, 5, 7 section Item C Find C :c1, 0, 3 Verify C :c2, 3, 6

workflow(nameOrRef, args)

脚本里可以调用另一个 workflow:

const research = await workflow("deep-research", {
  question: "How does this API migration affect SDK users?",
})

子 workflow 共享父 workflow 的 concurrency cap、agent counter、abort signal 和 token budget。子 workflow 的 agents 会在 /workflows 中显示为 child group。嵌套限制为一层,child workflow 里再调用 workflow() 会失败。

Scheduler And Backpressure

Dynamic Workflow 可以让主 Claude 写循环和 fan-out,但 runtime 会限制吞吐:

边界当前观察到的行为
本地 agent 并发大致 min(16, cpu cores - 2),下限 2。
远端 agent 并发有独立 cap,当前观察到常量为 50。
单 workflow lifetime agent cap1000。
单个 array boundary cap4096。
token budgethard ceiling,达到后不再启动新 agent。
in-flight agentsbudget hit 后,已在飞的结果会尽量保留。

budget 暴露给脚本:

while (budget.total && budget.remaining() > 50_000) {
  const round = await agent("Find more distinct bugs.", { schema: BUGS_SCHEMA })
  log(`${round.bugs.length} candidates, ${Math.round(budget.remaining() / 1000)}k tokens left`)
}

budget.remaining() 在没有 token target 时是 Infinity。所以 budget-driven loop 必须 guard budget.total。runtime 也有 1000 agent cap 作为 runaway-loop backstop。

Subagent Execution Model

默认 subagent type 是内置 workflow-subagent。它拥有 session 工具能力,但会被禁止使用一些会破坏返回值协议或导致递归编排的工具,例如直接向用户发消息、再启动某些 agent/workflow 入口等。

subagent prompt 的关键语义:

  • final text 是 agent() 的返回值。
  • 如果要求 JSON,应返回 raw JSON,不要 code fence 和解释。
  • 不要用面向用户的确认语,例如 “Done”。
  • 有 schema 时,必须调用 StructuredOutput 工具。

agentType 可以切换到已有 custom agent:

const plan = await agent("Design the migration plan.", {
  agentType: "software-architect",
  schema: PLAN_SCHEMA,
})

schema 会和 custom agent prompt 组合。换句话说,Dynamic Workflow 可以复用 agent registry,同时把返回值边界收紧成 structured output。

isolation: "worktree" 会给 subagent 创建独立 git worktree。适合并行修改文件的场景,成本包括 worktree 创建、磁盘占用、最终 cleanup 或保留 review。远端 isolation 有单独路径和 UI 文案;当前本机 build 中,本地 agent call 对 isolation: "remote" 可能直接拒绝,因此写 workflow 时要按环境能力降级。

Structured Output As Harness Boundary

对 harness 来说,schema 是 data plane。

无 schema:

const text = await agent("Summarize the migration risk.")

有 schema:

const VERDICT_SCHEMA = {
  type: "object",
  required: ["isReal", "confidence", "reason"],
  properties: {
    isReal: { type: "boolean" },
    confidence: { enum: ["high", "medium", "low"] },
    reason: { type: "string" },
  },
}

const verdict = await agent("Try to refute this finding.", {
  schema: VERDICT_SCHEMA,
})

schema 让 downstream 代码可以做:

  • dedupe by file / line / claim id
  • filter by confidence
  • majority vote
  • rank by severity
  • join source metadata
  • cap final report length
  • collect caveats and dropped coverage

这是 multi-agent harness 的常见分界线:LLM 负责非结构化探索和判断,workflow code 负责集合操作、控制流和可审计的筛选逻辑。

Resume Journal And Cache Key

每个本地 workflow run 都会关联一个 journal。当前观察到 journal 是 journal.jsonl,主要记录两类事件:

{"type":"started","key":"v2:...","agentId":"..."}
{"type":"result","key":"v2:...","agentId":"...","result":{...}}

resume 时,runtime 会 load journal,构建:

  • results: Map<key, resultEvent>
  • started: Map<key, startedEvents[]>

agent call 的 resume key 比 prompt hash 更细。它更接近下面这个结构:

keyN = "v2:" + sha256(
  previousKey + "\0" +
  prompt + "\0" +
  canonicalize({
    schema,
    model,
    effort,
    isolation,
    agentType
  })
)

进入 key 的 opts subset:

opts 字段进入 resume key
schemayes
modelyes
effortyes
isolationyes
agentTypeyes
labelno
phaseno
stallMsno

chain key 的效果很实际:如果你在前面插入一个新的 agent(),后面的 previousKey 会变化,后续 agent 的 key 会自然失效。这样可以避免脚本控制流变化后误复用旧结果。

flowchart TD A1["agent call 1"] --> K1["key1 = hash(empty + prompt1 + opts1)"] K1 --> A2["agent call 2"] A2 --> K2["key2 = hash(key1 + prompt2 + opts2)"] K2 --> A3["agent call 3"] A3 --> K3["key3 = hash(key2 + prompt3 + opts3)"] E["edit: insert new call before call 2"] --> NK1["key1 unchanged"] NK1 --> NX["new inserted key"] NX --> NK2["old call 2 gets new previousKey, cache miss"]

这个设计支持“最长未变化前缀复用”。同一个 script、同一个 args、同样 agent call 顺序时,resume 可以直接命中已完成结果。修改中间控制流后,从第一个受影响调用开始重跑。

Progress Projection

进度条和 /workflows 视图来自 runtime 的状态投影。runtime 会产生三类进度实体:

类型典型字段
workflow_phaseindex, title, kind
workflow_agentindex, label, phaseIndex, state, tokens, toolCalls, durationMs, error
workflow_logmessage

task registry 对 workflow_phaseworkflow_agent 做 upsert,key 类似 type:index。log 则追加,并有截断策略。task 会派生:

  • agentCount
  • totalTokens
  • totalToolCalls
  • progressVersion
  • per-agent state
  • phase grouping
flowchart TD Runtime["Workflow runtime"] --> Phase["workflow_phase"] Runtime --> Agent["workflow_agent"] Runtime --> Log["workflow_log"] Phase --> Task["LocalWorkflowTask.workflowProgress"] Agent --> Task Log --> Task Task --> Derived["agentCount / tokens / toolCalls / progressVersion"] Derived --> UI["/workflows progress tree"] UI --> Actions["pause / kill / skip agent / retry agent"] Actions --> Runtime

所以进度百分比更接近“已完成 agent / 已知 agent group / phase 状态”的执行进度。它不能代表模型内部认知百分比。模型本身无法可靠报告“思考完成 37%”;runtime 可以可靠知道哪些 agent 已启动、哪些完成、哪些失败、当前 token 和 tool call 计数是多少。

Failure Semantics

Dynamic Workflow 的工程价值很大一部分来自失败语义。常见情况如下:

情况行为
单个 agent() terminal API error记录 workflow log,通常返回 null 给分支。
parallel() slot throw对应 slot 变 null,整体 parallel() 返回数组。
pipeline() item throw该 item 变 null,剩余 stages 跳过。
user skip agent当前 agent abort,结果为 null,progress 标记 skipped。
user retry agent当前 attempt abort,进入 retry attempt。
stall长时间无进展后标记 stalled,并重试到 cap。
structured output validation failure继续要求 StructuredOutput,直到 retry cap。
degraded / throttle-like responsebackoff 后重试一次。
budget exceeded不再启动新的 agent,已在飞 agent 的结果尽量保留。
workflow abort根据原因进入 paused、killed 或 failed 状态。

这和普通对话里的“让模型继续试试”不同。workflow runtime 把失败变成可记录、可投影、可恢复的状态。脚本作者可以把 null 当作数据处理,例如 .filter(Boolean)、记录 dropped coverage、进入下一轮补扫。

Built-in Workflow Patterns

当前版本能看到两个很能说明设计意图的内置 workflow。

code-review

大致模式:

flowchart TD Scope["Scope: pin diff/files/conventions"] --> Find["Find: independent review angles"] Find --> Verify["Verify: independent verifier per candidate"] Verify --> Sweep["Sweep: gap finder for higher effort"] Sweep --> Synth["Synthesize: merge duplicates, rank, cap report"]

它把 code review 拆成 recall-oriented finder、candidate verification、gap sweep、final synthesis。高 effort 下增加角度数量、候选数量和 sweep,避免只依赖单个 agent “更努力地想”。

deep-research

大致模式:

flowchart TD Scope["Scope: decompose question into search angles"] --> Search["Search: parallel WebSearch agents"] Search --> Fetch["Fetch: URL dedupe + extract claims"] Fetch --> Verify["Verify: adversarial votes per claim"] Verify --> Report["Synthesize cited report"]

这个 workflow 更像 research harness:多角度搜索、URL 去重、抽取 falsifiable claims、对 claim 做 adversarial verification、最后生成带 caveats 的报告。

这些内置 workflow 暗示了 Dynamic Workflow 的目标场景:高 recall、可验证、多阶段、可结构化汇总。

Harness Patterns

以下 pattern 都能直接映射到 Dynamic Workflow 的 primitives。

Pattern结构
Exhaustive reviewfinder pool -> dedupe -> verifier panel -> synthesize
Deep researchsearch angles -> fetch/extract -> claim verification -> cited report
Incident diagnosislogs/diff/config/history 并行收集 -> root cause voting -> fix plan
Migration reviewmodule inventory -> compatibility check -> rollout plan -> risk table
Large repo tracingconfig/protocol/handler/UI/test 多线调查 -> data-flow synthesis
Loop until dryfinder rounds until N consecutive rounds produce no fresh candidates
Budget-scaled audit根据 budget.total 自动决定 finder 数量、round 数和 verifier 票数
Judge panel多方案生成 -> independent scoring -> winner synthesis
Perspective-diverse verifycorrectness/security/perf/repro 不同 lens 投票

一个 compact 的 loop-until-dry skeleton:

const seen = new Set()
const confirmed = []
let dryRounds = 0

while (dryRounds < 2 && (!budget.total || budget.remaining() > 50_000)) {
  const found = await parallel(
    FINDERS.map((finder) => () =>
      agent(finder.prompt, { phase: "Find", schema: FINDINGS_SCHEMA })
    )
  )

  const fresh = found
    .filter(Boolean)
    .flatMap((r) => r.findings)
    .filter((f) => !seen.has(keyOf(f)))

  if (fresh.length === 0) {
    dryRounds++
    log(`dry round ${dryRounds}/2`)
    continue
  }

  dryRounds = 0
  fresh.forEach((f) => seen.add(keyOf(f)))

  const judged = await parallel(
    fresh.map((finding) => () =>
      parallel(
        ["correctness", "security", "repro"].map((lens) => () =>
          agent(verifyPrompt(finding, lens), {
            phase: "Verify",
            schema: VERDICT_SCHEMA,
          })
        )
      ).then((votes) => ({ finding, votes: votes.filter(Boolean) }))
    )
  )

  confirmed.push(...judged.filter(Boolean).filter(isMajorityReal))
}

return { confirmed, seen: seen.size }

这个例子展示了三件事:

  • LLM 负责找候选和判断。
  • JS 负责 loop、dedupe、vote、budget guard。
  • runtime 负责并发、进度、重试、恢复和上限。

Agent Team Comparison

Agent Team 和 Dynamic Workflow 都能多 agent。区别主要在 coordination surface。

维度Agent TeamDynamic Workflow
协调者主 Claude / 用户workflow script
控制流对话和自然语言ifforparallel()pipeline()
返回值message / transcript / summarystring / structured object / JSON-like result
状态agent/task 状态phase、agent、log、journal、snapshot
恢复依赖继续对话和 transcript 理解scriptPath + resumeFromRunId
复用协作现场workflow file、project workflow、plugin workflow
适合模糊探索、人工插手频繁流程明确、可重复、需结构化和恢复

实际使用上可以组合:先用 Agent Team 探索任务边界,等流程稳定后沉淀成 workflow。也可以让 Dynamic Workflow 在某个 stage 使用 custom agentType,把已有 agent 专长纳入脚本化 harness。

Design Lessons For Harness Engineers

Dynamic Workflow 里最值得借鉴的设计点:

  1. Deterministic control plane 让编排逻辑运行在受限、可检查、可重放的语言子集里。

  2. Structured data plane 用 schema 把 agent output 变成程序变量,避免只留下自然语言 transcript。

  3. Artifact-based iteration scriptPath 让 workflow 可以被 review、edit、rerun、resume。

  4. Journaled resume startedresult 事件足以支持 agent-call 级别复用。chain key 让控制流变化自动失效。

  5. Observable projection runtime 发 phase/agent/log,UI 只做 task projection。这样 CLI、后台任务、notification、SDK event 都能共享同一状态源。

  6. Backpressure first concurrency cap、agent cap、array cap、budget hard ceiling 都属于 harness 核心边界。

  7. Failure as data branch failure 返回 null、log 记录原因、progress 标记状态。脚本可以继续处理剩余集合。

  8. Composable but bounded nesting workflow() 支持子流程复用,同时限制一层嵌套,避免 orchestration recursion 失控。

  9. Human controls stay in the loop pause、kill、skip、retry 直接作用于 runtime task / agent controller,无需让模型“理解用户想停哪个”。

  10. Budget-aware autonomy budget 暴露给脚本后,workflow 可以实现“按预算扩展深度”,支持动态调整 fan-out。

Closing

Dynamic Workflow 把 Claude Code 的多 agent 能力组织成一个可执行 runtime:主 Claude 写控制流,JS VM 执行控制流,subagents 执行具体认知任务,journal 支持恢复,task projection 支持观察和控制。

对 agent / harness 工程师来说,重点不在“能同时启动几个 agent”。重点在这一组边界:deterministic script、structured output、bounded scheduler、journaled resume、observable task state、budget-aware loops。

这些边界合在一起,才让多 agent 协作从一次性的对话现场,进入可调试、可恢复、可复用的工程系统。