Compress ZH/EN/JA essay into problem → ASCII/figure → minimal code → try it. Move pattern grid, quarantine, primitives card, and overview SVG into details; bump translation-sync to v18. Co-authored-by: Xinlu Lai <CrazyBoyM@users.noreply.github.com>
6.7 KiB
s16: Workflow Runtime — Put the Recipe in Code
s01 → ... → s14 → s15 → s16 → s17
Workflow = orchestration written as code. Script owns topology; the model judges each step.
Harness layer: Orchestration — a multi-agent script above the single-agent loop.
Trust the model. Engineer the harness. Workflows take that one floor up.
Problem
On long jobs, plan and action share one chat: stop early, grade your own homework kindly, lose quiet constraints after compressions. Soft chat memory is a weak place for parallelism, stable result shapes, and resume.
Nudging turn-by-turn is like texting the chef every ten seconds. A workflow is a recipe the kitchen can follow.
Idea
Helpers (subagents) still think. The script owns loops, fan-out, and merge. Intermediates live in variables and a journal — not the conversation.
Orchestration moves from intelligence to structure.
messages[] ──► Workflow(...) ──► tool_result
│
▼
script owns: agent / parallel / pipeline
│
▼
variables + journal
One Workflow tool call starts the run; one result comes back when it finishes.
Two doors
- Dynamic: model writes a JS orchestration script for this task (
script/scriptPath). - Saved: good script under
.claude/workflows/; call byname+args. - Static (cousin outside): Agent SDK /
claude -pwritten ahead — usually more generic.
Left: fixed pipeline → generic report. Right: cut for your code → a specific recommendation.
This chapter is a Python teaching runtime (no JS VM). Concepts map to Claude Code; the demo uses the Saved door. In the product the model can submit executable scripts — we just skip embedding a JS interpreter here.
# teaching sketch — not the full schema
Workflow({ "name": "review-changes", "args": { "changes": "..." } })
# Claude Code also accepts: script | scriptPath | resumeFromRunId
Three verbs
agent one helper, one job (optional schema → validated JSON)
pipeline each item walks stages alone (default — no barrier)
parallel wait for every tray (barrier — use sparingly)
On failure the fleet continues: parallel → null in that slot; pipeline drops that item and its later stages. Filter before merge.
Resume: journal records calls in invocation order; replay the longest unchanged prefix, then run live. Real JS runtimes ban Date.now() / Math.random(). This demo does not fully sandbox that — write deterministic scripts anyway.
journal [A] [B] [C] [D]
resume hit hit ✂ live
Official primitive card + quieter verbs
agent; parallel (barrier) vs pipeline (streaming stages). Claude Code also has model / isolation / agentType; teaching surface is smaller.
Quieter: phase, log, nested workflow, args, budget.
Two shapes + one sample
Feel two first (full six-pattern grid in the fold below):
Fanout task ──► ● ● ● ● ══barrier══► synthesize
Adversarial worker ──► verifier×N → keep what still stands
Sample review-changes = Fanout with Adversarial inside: pipeline(audit, verify) per dimension; parallel verifiers; keep only isReal.
correctness ── audit ── verify ──┐
security ── audit ── verify ──┤── confirmed
performance ── audit ── verify ──┤
style ── audit ── verify ──┘
# from code.py (abbreviated)
async def sample_workflow(ctx, args):
ctx.phase("Review")
results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]]
return {"confirmed": confirmed}
The fleet cannot stop early, the author is not the judge, and topology is not rewritten every chat turn.
Six-pattern grid + primitive map
| Pattern | Primitive sketch | Skip when… |
|---|---|---|
| Classify-And-Act | agent → branch → agent |
Same treatment for every item |
| Fanout-And-Synthesize | pipeline / parallel → merge |
One pass already fits |
| Adversarial Verification | produce → parallel(verify) → filter |
A wrong answer is cheap |
| Generate-And-Filter | parallel(gens) → filter |
Answer space is already tiny |
| Tournament | pairwise judge agents |
A clear rubric picks a winner |
| Loop Until Done | while + stop + budget |
Work size is known |
# teaching sketch
kind = await ctx.agent("classify this ticket", schema=KIND)
if kind["type"] == "billing":
return await ctx.agent("handle billing…")
Untrusted input: quarantine
The agent that reads tickets should not also hold PR keys. Readers stay read-only → structured summary; a trusted actor acts on the summary only.
backlog (untrusted) → [quarantine: readers → dedupe → summary] → [trusted: actor]
High-privilege tools stay on the trusted side. Pair with /loop if the backlog never sleeps.
How this hangs on s15
s15 stays the host loop; s16 only adds a Workflow tool. Product runs can be background; the teaching CLI keeps demo / resume in the foreground for phases and cache hits.
Neighbors & when not
Who holds the plan? s06 one-shot delegate, s13 mailbox peers, s15 one loop, s16 script + journal, s17 asks “is the whole goal done?”
Ordinary coding: one s15 turn or one honest s06 often wins. Workflows cost tokens and coordination — reach for them when structure must outlast a single context.
Try it
python s16_workflow_runtime/code.py # s15 host + Workflow (real API)
python s16_workflow_runtime/code.py demo # fixed fixture; watch phases
python s16_workflow_runtime/code.py resume # same runId; expect cache hits
A full resume should show agents=0 tokens=0.
Next
s16 is how a batch runs. s17 Goal Loop asks: stop, or take another turn?



