diff --git a/s16_workflow_runtime/README.ja.md b/s16_workflow_runtime/README.ja.md
index d42c7c9b..5b992f55 100644
--- a/s16_workflow_runtime/README.ja.md
+++ b/s16_workflow_runtime/README.ja.md
@@ -4,114 +4,78 @@
s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](../s17_goal_loop/)
-> *「ターンごとのチャットは、10 秒ごとにシェフへメールするようなものです。Workflow は厨房が従えるレシピです。」*
+> Workflow = コードに書いたオーケストレーション。トポロジはスクリプト、一歩の判断はモデル。
>
-> **Harness 層**: Orchestration — single-agent loop の上に multi-agent script を載せます。
+> **Harness 層**: オーケストレーション — 単一 agent ループの上で多 agent スクリプトを回す。
>
-> モデルを信頼し、harness をエンジニアリングする。Workflow は、その考えを一階上げたものです。
+> モデルを信じ、harness を設計する。Workflow はその一言を一段上げる。
---
-友だちとチャットだけで料理しているところを想像してください。「玉ねぎを切って」。待つ。「できた?」。次はフライパン、塩。一品ならそのリズムでも持ちます。二十卓の宴会では持ちません。手順は抜け、同じ言葉が返り、スマホが落ちたら冷たいところからやり直しです。
+## 問題
-モデルがシェフとクリップボードを兼ねるときも、同じ感触です。計画と実行が一つの会話に押し込まれます。**Workflow** は書かれたレシピです。厨房(小さな runtime)がそれに従い、助手(subagent)が味見と判断をし、仕掛かりの器はカウンターに——変数と journal に——置かれます。グループスレッドの中ではありません。
+長い仕事では計画と実行が同じ chat に同居する:途中で完了宣言、自分の宿題を甘く採点、圧縮のあと静かな制約が消える。並列・安定した結果形・再開——柔らかい会話メモリでは支えきれない。
-## なぜ、もう一枚の harness が要るのか
+十秒おきにシェフへ SMS を送るような催促。**Workflow** は厨房がそのまま従えるレシピだ。
-デフォルトの Claude Code harness は、コーディング型の仕事にもう十分強いです。直す、走らせる、エラーを読む、また試す。一つのループ。一つの頭。かなりの手業が出ます。
+## アイデア
-ただ、ある仕事にはその上に**定制の harness** が要ります。深い調査、セキュリティの洗い出し、agent teams、変更一式を広げて review するような仕事です。SDK で先に手書きしてもよい。あるいは——ここが生きているところですが——Claude に**このタスク用**の harness を書かせ、走らせ、良いものを残せます。
+ヘルパー(サブ agent)は考える。**スクリプト**がループ・分散・マージを握る。中間結果は変数と journal に置き、会話には入れない。
-コースのモットーを一階上げると、こうなります。各ステップの中ではモデルを信頼する。ステップの並びは、自分で形を決める。
-
-## 長いチャットが静かにやりがちなこと
-
-s01 から s15 まで、計画と行動は同じ context window を共有します。次の一手が直前の発見に依るときは心地よいです。仕事が長く、大規模に並行し、硬い構造を求め、あるいは疑り深い第二意見が要ると、脆くなります。
-
-長いチャットをじっと見ていると、用語を覚える前に癖に出会います。50 項目のうち 35 で勝利宣言をする。自分の宿題を採点させると甘くなる——狐が鶏小屋を採点する。多ターンと圧縮のあいだに、「X には触るな」が薄れていく。
-
-それが agentic laziness、self-preferential bias、goal drift です。名前より感触が大事です。仕事をする窓が、計画を覚える窓でもある。柔らかい会話メモリは、並行性や安定した結果の形、再開を預けるには弱い場所です。
-
-## アイデアが落ちる瞬間
-
-もし計画がコードの中に住んだらどうでしょう。
-
-助手は相変わらず考えます——きれいな机で。**script** がループと扇状の分配とマージを持ちます。中間結果は変数と journal にあり、会話には入りません。途中で切り上げる癖は艦隊を止めにくくなり、自己採点の甘さは著者ではない第二の助手にぶつかり、drift も掴みにくくなります。
-
-**Workflow はオーケストレーションを「賢さ」から「構造」へ移します。** モデルは各 `agent()` の中で判断し、地図は script が持ちます。
+**オーケストレーションを「知性」から「構造」へ移す。**
```text
- messages[] ──► Workflow(...) ──► tool_result { launched, result, task }
+ messages[] ──► Workflow(...) ──► tool_result
│
▼
- ┌───────────────┐
- │ script が │
- │ topology を持つ│
- └───────┬───────┘
- │ agent / parallel / pipeline
+ スクリプトが握る: agent / parallel / pipeline
+ │
▼
変数 + journal
```
-1 回の `Workflow` tool call が、その実行を始めます。進み具合は途中で小さく鳴り、レシピが終わると一つの tool result が戻ります。
+`Workflow` ツール呼び出しひとつで開始;レシピが終わると結果がひとつ返る。
-Runtime 概要図(任意)
+Runtime 概要図

-## ふたつの入口——そして外のいとこ
+## ふたつの入口
-Claude Code は入口について率直です。
+- **Dynamic**: モデルが*この*タスク向けに JS オーケストレーションを書く(`script` / `scriptPath`)。
+- **Saved**: 良いスクリプトを `.claude/workflows/` に置き、`name` + `args` で再呼び出し。
+- **Static**(外のいとこ): SDK / `claude -p` で事前に書く——だいたい汎用寄り。
-**Dynamic** — モデルが*この*タスク用の JavaScript オーケストレーションを書く(`script`、あとから `scriptPath`)。問題がまだ熱いうちに裁断する harness。
+
-**Saved** — 良い script がすでに `.claude/workflows/` のような場所にある。`name` + `args` で呼び出す。残すに値した run が、再利用できるカードになったものです。
+*左: 固定パイプライン → 汎用レポート。右: あなたのコード向けに裁断 → 具体的な提案。*
-外にはいとこもあります。**static** harness を Agent SDK や `claude -p` で先に書くやり方です。あらゆるエッジケースに耐える必要があるので、どうしても汎用になります。dynamic はこの布のための裁断です。形が合ったら保存します。
-
-
-
-*同じ問い、ふたつの harness。左: 固定の検索→検証→要約 → 汎用レポート。右: billing コードを読み、分岐し、devil's advocate を呼ぶ → 具体的な推奨。*
-
-**この章は Python の teaching runtime です。** 同じアイデアを、1 行ずつ読める形で示します。デモは名前で一つの saved workflow を登録します。概念は Claude Code の script 世界と 1:1 です。「モデルは実行可能コードを渡せない」などと言いません——それは Claude Code については初めから正しくありませんでした。ここでは JS インタプリタを埋め込まないだけです。
+本章は **Python のティーチング runtime**(JS VM なし)。概念は Claude Code に揃え、デモは Saved 入口。製品ではモデルが実行可能スクリプトを出せる——ここでは JS インタプリタを埋め込まないだけ。
```python
-# teaching sketch — saved の入口(完全な Claude Code schema ではない)
+# teaching sketch — 完全な schema ではない
Workflow({ "name": "review-changes", "args": { "changes": "..." } })
-
-# Claude Code は他にも受け付ける: script | scriptPath | resumeFromRunId
+# Claude Code はさらに: script | scriptPath | resumeFromRunId
```
-## スクリプトが話す三つの動詞
-
-学校のバザー。どのテーブルも 混ぜる → 焼く → 箱詰め。助手が味見をし、レシピが順番を決めます。
+## 三つの動詞
```text
- agent 助手ひとり、仕事ひとつ
- pipeline 各ケーキが自分で stage を歩く (既定 — barrier なし)
- parallel すべてのトレイが戻るまで待つ (barrier — 控えめに)
+ agent ヘルパー一人、仕事ひとつ(schema で JSON 検証可)
+ pipeline item ごとに段階を進む(既定 — 障壁なし)
+ parallel 全部揃ってから次へ(障壁 — 控えめに)
```
-`agent(prompt, opts?)` は助手ひとりに頼みます。`schema` があれば検証済み JSON が返り——次の段が受け取れるソケットになり——最初が雑なら一回だけやり直せます。
+失敗しても艦隊は続く: `parallel` はそのスロットが `null`;`pipeline` は**その item** と後段を落とす。マージ前にフィルタ。
-`pipeline` はケーキ A が箱詰めのあいだに、ケーキ B がまだ混ぜていてもよい形です。`parallel` は次の段が本当に全部の結果を要すときだけ——トレイ全部を味見してから採点表を書く、といった場面です。
-
-```python
-# teaching sketch — 形だけ(実行可能な sample は code.py)
-results = await ctx.pipeline(DIMENSIONS, audit, verify)
-confirmed = [f for r in results if r for f in r["confirmed"]]
-```
-
-助手が失敗しても艦隊は優しくいられます。`parallel` の失敗はそのスロットで `null`、`pipeline` の失敗は**その item** を落として残りの stage を飛ばします。マージの前に絞ります。
-
-厨房が止まったら? disk 上の journal が*呼び出し順*で各 call を覚えます。resume は**最長の未変更プレフィックス**を再生し、最初の変更から先は live。本物の JS runtime は `Date.now()` / `Math.random()` を禁じてノートを揃えます。この Python デモはそのサンドボックスまではやりません——それでも script は決定的に書いてください。
+再開: journal は呼び出し順に記録;**最長の未変更プレフィックス**を再生し、最初の変更以降は実走。本物の JS runtime は `Date.now()` / `Math.random()` を禁じる。このデモは完全サンドボックスしない——それでも決定的に書く。
```text
- journal [A] [B] [C] [D]
- resume hit hit ✂ live ← プレフィックスは C で切れる
+ journal [A] [B] [C] [D]
+ resume hit hit ✂ live
```
@@ -119,157 +83,104 @@ confirmed = [f for r in results if r for f in r["confirmed"]]

-*公式カード: `agent`、そして `parallel`(barrier)と `pipeline`(streaming stages)。Claude Code には `model` / `isolation` / `agentType` もあります。teaching runtime は表面を小さく保ちます。*
+*`agent`;`parallel`(障壁)vs `pipeline`(ストリーミング段階)。Claude Code には `model` / `isolation` / `agentType` もある;ティーチング面は小さめ。*
-静かな動詞: `phase`、`log`、入れ子の `workflow`(1 段)、`args`、`budget`。
+静かな動詞: `phase`、`log`、ネスト一段 `workflow`、`args`、`budget`。
-## レシピが書けるようになったら——パターンの道具箱
+## ふたつの形 + ひとつの sample
-動詞は小麦粉と火加減です。人が何度も発明し直すのは、少数の*形*——道具箱であり、必点メニューではありません。
-
-
-
-*公式の六パターン格子。トポロジーは script が持ち、このレッスンでは `agent` / `parallel` / `pipeline` / journal で各形を話します。*
-
-このあとのサンプルのために、いちばん大事な三つを先に感じてください——名前はあとからでよいです。
-
-**Fanout-And-Synthesize** — 五十ファイルは一つの疲れた context に入りません。分け、多く走らせ、barrier でまとめます。
+まずふたつ(六パターン全体は下の折りたたみ):
```text
- task ──► ● ● ● ● ══barrier══► synthesize
+ Fanout task ──► ● ● ● ● ══barrier══► synthesize
+ Adversarial worker ──► verifier×N → 残るものだけ残す
```
-**Adversarial Verification** — 狐が鶏小屋を採点してはいけません。worker が出し、独立した verifier が突き、立っているものだけ残します。
-
-```text
- worker ──► verifier
- ├──► verifier
- └──► verifier → まだ立つものだけ
-```
-
-**Generate-And-Filter** — 欲しいのは選択肢であり、最初に賢く聞こえた案ではありません。多くの generator、そのあと rubric(と dedupe)。
-
-同じ道具箱には **Classify-And-Act**(専門家へ振り分け)、**Tournament**(ペア審判で勝者)、**Loop Until Done**(「新しい発見?」が yes のあいだ spawn、硬い `budget` 付き)もあります。コストが明瞭さや安全を買うときだけ、スタイルを借ります。
-
-
-各パターンをこのレッスンのプリミティブへ写す
-
-| パターン | プリミティブの素描 | 使わないとき |
-|----------|--------------------|--------------|
-| Classify-And-Act | `agent` → 分岐 → `agent` | 全部が同じ扱いでよい |
-| Fanout-And-Synthesize | `pipeline` / `parallel` → 統合 | 一通しでもう足りる |
-| Adversarial Verification | 生産 → `parallel(verify)` → filter | 間違えても安い |
-| Generate-And-Filter | `parallel(gens)` → filter | 良い答えの空間がもともと狭い |
-| Tournament | pairwise 審判 `agent` | 鋭い rubric が一通しで決める |
-| Loop Until Done | `while` + 停止 + `budget` | 仕事量が分かっている |
-
-```python
-# teaching sketch — 分類してから動く
-kind = await ctx.agent("この ticket を分類", schema=KIND)
-if kind["type"] == "billing":
- return await ctx.agent("billing を処理…")
-```
-
-組み合わせはふつうです。深い調査はしばしば fanout → filter → verify → synthesize と重ねます。
-
-
-
-### 信頼できない入力に workflow が出会うとき
-
-サポートチケットやユーザーフィードバックは信頼できません。それらを*読む* agent に、PR を開ける鍵まで持たせたくありません。エアロックを残します。reader は read-only のまま、構造化 summary だけを渡し、trusted な actor は summary にだけ作用する——生本文には触れない。
-
-```text
- backlog (untrusted)
- │
- ▼
- ┌─ QUARANTINE (read-only) ─┐
- │ readers → dedupe → summary │
- └────────────┬───────────────┘
- ▼
- ┌─ TRUSTED (high privilege) ─┐
- │ actor → fix / escalate │
- └─────────────────────────────┘
-```
-
-
-公式 quarantine 図
-
-
-
-*Reader は quarantine で分類と dedupe をし、高権限ツールは trusted 側に住みます。バックログが眠らないなら `/loop` と組んでもよいです。*
-
-
-
-## `review-changes` を歩く — ひとつの composition
-
-サンプルは「一つのパターン」ではありません。**Fanout-And-Synthesize** の中に **Adversarial Verification** が入り、終わりで軽く filter がかかる——`isReal` の finding だけが残ります。
+sample `review-changes` = **Fanout** の中に **Adversarial**: 次元ごとに `pipeline(audit, verify)`、`verify` 内で `parallel` 検証、`isReal` だけ残す。
```text
correctness ── audit ── verify ──┐
security ── audit ── verify ──┤── confirmed
performance ── audit ── verify ──┤
style ── audit ── verify ──┘
- fanout ▲ synthesize
- └── 各 finding の懐疑的 verify
```
-`pipeline(DIMENSIONS, audit, verify)` が各 dimension に机を渡します。`verify` 内の verifier の `parallel` が敵対の和音です。リスト filter が synthesize。`phase` が Review → Verify を印し、journal が各 `agent()` を覚えるので、止まっても audit をやり直さない。
-
-三つの癖が席を失う感触があります。艦隊は二つの dimension で止められず、著者は審判ではなく、トポロジーは途中で漂いません。
-
```python
-# code.py より — 実行可能な sample(短縮)
+# code.py から(抜粋)
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"]]
- ctx.log(f"{len(confirmed)} 件の実在する問題を確認")
return {"confirmed": confirmed}
```
+艦隊は早止めできず、作者は審判にならず、トポロジは chat の毎ターンで書き換わらない。
+
-s15 に掛けて(置き換えない)
+六パターン格子 + プリミティブ対応
-s15 は依然として host loop です。s16 が足すのは `Workflow` tool だけです。あなた(またはモデル)が saved の名前を頼み、adapter が script を走らせます。
+
-本番では背景+通知で置けます。teaching CLI は `demo` / `resume` を前景に置き、phase と cache hit を追いやすくしています。アイデアは同じで、簡略化は明示します。
+| パターン | プリミティブ速写 | 使わないとき |
+|----------|------------------|--------------|
+| Classify-And-Act | `agent` → 分岐 → `agent` | 全部同じ扱いでよい |
+| Fanout-And-Synthesize | `pipeline` / `parallel` → マージ | 一回で収まる |
+| Adversarial Verification | 生成 → `parallel(verify)` → フィルタ | 間違っても安い |
+| Generate-And-Filter | `parallel(gens)` → フィルタ | 答え空間がもともと狭い |
+| Tournament | 一対一の審判 `agent` | 明確な尺度で一発選定可 |
+| Loop Until Done | `while` + 停止 + `budget` | 仕事量が既知 |
+
+```python
+# teaching sketch
+kind = await ctx.agent("このチケットを分類", schema=KIND)
+if kind["type"] == "billing":
+ return await ctx.agent("請求を処理…")
+```
-## 宝石を回す: 計画を握っているのは誰か
+
+信頼できない入力: quarantine
-役に立つ問いは「agent は何人か?」ではなく、**トポロジーを誰が持つか**、仕掛かりの器はどこに置かれるか、です。
+チケットを*読む* agent が PR を開く鍵まで持つべきではない。reader は読み取りのみ → 構造化サマリ;trusted actor はサマリだけ見て動く。
-| 近所 | 計画を握るもの | 中間結果の置き場 | 向いている用途 |
-|------|----------------|------------------|----------------|
-| [s06 Subagent](../s06_subagent/) | モデル、一度きり | ほとんど捨てる | 汚い子タスクの隔離 |
-| [s13 Agent Teams](../s13_agent_teams/) | Lead + mailbox | 共有タスク / メッセージ | 長時間の同僚 |
-| [s15 Integrated Harness](../s15_integrated_harness/) | 一つのループ内のモデル | `messages[]` | 積み上げ型 coding agent |
-| **s16 Workflow** | **Script** | **変数 + journal** | 構造化した fan-out + verify |
-| [s17 Goal Loop](../s17_goal_loop/) | 停止時の evaluator | 会話を証拠に | 「ゴール全体は終わったか?」 |
+```text
+ backlog(非信頼)→ [quarantine: readers → 重複除去 → summary] → [trusted: actor]
+```
-より安い道もしばしば勝ちます。skill を軟らかい計画にする、短い multi-agent の会話、手書きの static orchestrator、あるいは大きな一回のモデルターン。構造が単一の context より長く生きねばならないときに、workflow へ手を伸ばします。
+
-## 棚に戻しておくとき
+*高権限ツールは trusted 側。バックログが眠らないなら `/loop` と組む。*
-Workflow は token と調整のコストを使います。ふつうのコーディングの大半は、五人の reviewer を必要としません。
+
-この仕事が本当にもっと計算と定制 harness を欲しがっているか、聞いてください。ふつうの s15 の一ターン——あるいは一つの誠実な s06 subagent——で足りるなら、そこで止めます。抑制も設計思想の一部です。
+
+s15 への掛け方
+
+s15 がホストループのまま;s16 は `Workflow` ツールを足すだけ。製品ではバックグラウンド可;ティーチング CLI は前景の `demo` / `resume` で段階とキャッシュを見せる。
+
+
+
+## 隣人と、使わないとき
+
+計画を握るのは誰か。s06 一回委譲、s13 メール箱の仲間、s15 単一ループ、**s16 スクリプト + journal**、s17 は「全体ゴールは終わったか」。
+
+普通のコーディングなら s15 一回、または正直な s06 で十分なことが多い。Workflow は token と調整コスト——構造が単一コンテキストより長生きすべきときだけ。
## 試してみる
```bash
-python s16_workflow_runtime/code.py # s15 host + Workflow(real API)
-python s16_workflow_runtime/code.py demo # 固定 fixture。phase を見る
-python s16_workflow_runtime/code.py resume # 同じ runId。cache hit を期待
+python s16_workflow_runtime/code.py # s15 ホスト + Workflow(本番 API)
+python s16_workflow_runtime/code.py demo # 固定データ;段階を見る
+python s16_workflow_runtime/code.py resume # 同じ runId;キャッシュ命中を期待
```
-Review が Verify に道を譲るのを見てください。完全な resume では agent が `cached` になり、`agents=0 tokens=0` と出るはずです——ノートが「温め直しは要らない」と言っている感じです。
+完全再開では `agents=0 tokens=0` になるはず。
## 次へ
-s16 はバッチの回し方です。[s17 Goal Loop](../s17_goal_loop/) は戸口で別の問いをします。止めるべきか、もう一ターンか。
+s16 はバッチの回し方。[s17 Goal Loop](../s17_goal_loop/) は聞く:止めるか、もう一周か。
-
+
diff --git a/s16_workflow_runtime/README.md b/s16_workflow_runtime/README.md
index cff7b978..e1e965cd 100644
--- a/s16_workflow_runtime/README.md
+++ b/s16_workflow_runtime/README.md
@@ -4,114 +4,78 @@
s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](../s17_goal_loop/)
-> *"Chatting turn-by-turn is like texting the chef every ten seconds. A workflow is a recipe the kitchen can follow."*
+> 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 are that idea one floor up.
+> Trust the model. Engineer the harness. Workflows take that one floor up.
---
-Picture cooking with a friend over text. “Chop the onions.” Wait. “Done yet?” Then the pan, then the salt. One dish survives that rhythm. A feast with twenty plates does not: you forget steps, repeat yourself, and if the phone dies you start over cold.
+## Problem
-That is what it feels like when one model is both chef and clipboard — planning and doing inside the same chat. A **workflow** is the written recipe. The kitchen (a small runtime) follows it. Helpers (subagents) taste and judge. Half-finished bowls sit on the counter — in variables and a journal — not in the group thread.
+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.
-## Why another harness at all?
+Nudging turn-by-turn is like texting the chef every ten seconds. A **workflow** is a recipe the kitchen can follow.
-The default Claude Code harness is already strong at coding-shaped work: change something, run it, read the error, try again. One loop. One mind. A surprising amount of craft.
+## Idea
-But some jobs want a **custom harness on top** — deep research, security sweeps, agent teams, a review that fans across a whole change set. You can hand-write that layer once in an SDK. Or — and this is the lively idea — Claude can draft a harness **for this task**, run it, and keep the good ones.
+Helpers (subagents) still think. The **script** owns loops, fan-out, and merge. Intermediates live in variables and a journal — not the conversation.
-Same course motto, raised one floor: trust the model inside each step; decide the shape of the steps yourself.
-
-## What a long chat quietly does wrong
-
-From s01 through s15, plan and action share one context window. Wonderful when the next move depends on what you just found. It frays when the job is long, massively parallel, rigidly structured, or needs a skeptical second opinion.
-
-Watch a long chat carefully and you will meet the habits before you learn their names. It gets tired and declares victory after thirty-five of fifty review items. Asked to check its own homework, it grades kindly — the fox scoring the henhouse. Across many turns and compressions, the quiet “don’t touch X” fades until nobody remembers why it was there.
-
-Those are agentic laziness, self-preferential bias, and goal drift. The names matter less than the feeling: the same window that does the work is also trying to remember the plan. Soft chat memory is a weak place to keep parallelism, stable result shapes, and resume.
-
-## The idea, once it clicks
-
-What if the plan lived in code?
-
-Helpers still think — each at a clean desk. The **script** owns loops, fan-out, and merge. Intermediate results live in variables and a journal, not in the conversation. Laziness struggles to stop the fleet early. Self-checking bias meets a second helper who was not the author. Drift loses its grip because the topology is not rewritten every turn by a tired narrator.
-
-**Workflows move orchestration from intelligence to structure.** The model still judges inside each `agent()`; the script owns the map.
+**Orchestration moves from intelligence to structure.**
```text
- messages[] ──► Workflow(...) ──► tool_result { launched, result, task }
+ messages[] ──► Workflow(...) ──► tool_result
│
▼
- ┌───────────────┐
- │ script owns │
- │ the topology │
- └───────┬───────┘
- │ agent / parallel / pipeline
+ script owns: agent / parallel / pipeline
+ │
▼
variables + journal
```
-One `Workflow` tool call starts that run. Progress ticks while it works; one tool result comes back when the recipe finishes.
+One `Workflow` tool call starts the run; one result comes back when it finishes.
-Runtime overview diagram (optional)
+Runtime overview diagram

-## Two doors — and a cousin outside
+## Two doors
-Claude Code is straightforward about how you enter.
+- **Dynamic**: model writes a JS orchestration script for *this* task (`script` / `scriptPath`).
+- **Saved**: good script under `.claude/workflows/`; call by `name` + `args`.
+- **Static** (cousin outside): Agent SDK / `claude -p` written ahead — usually more generic.
-**Dynamic** — the model writes a JavaScript orchestration script for *this* task (`script`, later `scriptPath`). A harness cut while the problem is still warm.
+
-**Saved** — a good script already lives under something like `.claude/workflows/`. You call it by `name` + `args`. The reusable residue of a run that earned its keep.
+*Left: fixed pipeline → generic report. Right: cut for your code → a specific recommendation.*
-Outside sits a cousin: **static** harnesses you write ahead with the Agent SDK or `claude -p`. Those must survive every edge case, so they stay generic. Dynamic ones are cut for *this* cloth; save them when the fit is right.
-
-
-
-*Same question, two harnesses. Left: fixed search→verify→summarize → a generic report. Right: read your billing code, branch, invite a devil’s advocate → a specific recommendation.*
-
-**This chapter is a Python teaching runtime.** Same ideas, every line readable. The demo registers one saved workflow by name; concepts map 1:1 to Claude Code’s script world. We will not pretend “the model cannot submit executable code” — that was never true of Claude Code. We simply skip embedding a JS interpreter.
+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.
```python
-# teaching sketch — saved door (not the full Claude Code schema)
+# teaching sketch — not the full schema
Workflow({ "name": "review-changes", "args": { "changes": "..." } })
-
# Claude Code also accepts: script | scriptPath | resumeFromRunId
```
-## Three verbs the script speaks
-
-School bake sale. Every table: mix → bake → box. Helpers taste; the recipe decides order.
+## Three verbs
```text
- agent one helper, one job
- pipeline each cake walks stages alone (default — no barrier)
- parallel wait until EVERY tray is back (barrier — use sparingly)
+ 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)
```
-`agent(prompt, opts?)` asks one helper. With `schema`, you get validated JSON — a socket the next stage can hold — and one retry if the first reply is messy.
+On failure the fleet continues: `parallel` → `null` in that slot; `pipeline` drops **that item** and its later stages. Filter before merge.
-`pipeline` lets cake A box while cake B is still mixing. `parallel` is for when the next step truly needs all results together — tasting every tray before the scorecard.
-
-```python
-# teaching sketch — shape only (see code.py for the runnable sample)
-results = await ctx.pipeline(DIMENSIONS, audit, verify)
-confirmed = [f for r in results if r for f in r["confirmed"]]
-```
-
-When a helper fails, the fleet stays kind: a `parallel` miss becomes `null` in that slot; a `pipeline` miss drops **that item** and skips its later stages. Filter before you merge.
-
-When the kitchen pauses, a journal on disk remembers calls in *invocation* order. Resume replays the **longest unchanged prefix**; at the first change, everything after runs live. Real JS runtimes ban `Date.now()` / `Math.random()` so the notebook stays aligned. This Python demo does not fully sandbox that — write deterministic scripts anyway.
+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.
```text
- journal [A] [B] [C] [D]
- resume hit hit ✂ live ← prefix breaks at C
+ journal [A] [B] [C] [D]
+ resume hit hit ✂ live
```
@@ -119,144 +83,91 @@ When the kitchen pauses, a journal on disk remembers calls in *invocation* order

-*Official card: `agent`, then `parallel` (barrier) vs `pipeline` (streaming stages). Claude Code also exposes `model` / `isolation` / `agentType`; our teaching runtime keeps a smaller surface.*
+*`agent`; `parallel` (barrier) vs `pipeline` (streaming stages). Claude Code also has `model` / `isolation` / `agentType`; teaching surface is smaller.*
-Quieter verbs: `phase`, `log`, nested `workflow` (one level), `args`, `budget`.
+Quieter: `phase`, `log`, nested `workflow`, `args`, `budget`.
-## Once you can write the recipe — the pattern toolbox
+## Two shapes + one sample
-The verbs are flour and heat. What people keep reinventing are a handful of *shapes* — a toolbox, not a mandatory menu.
-
-
-
-*Official six-pattern grid. Script owns topology; this lesson speaks each shape with `agent` / `parallel` / `pipeline` / journal.*
-
-Three shapes matter most for the sample ahead — feel them before the names pile up.
-
-**Fanout-And-Synthesize** — fifty files will not fit one tired context. Split, run many, merge at a barrier.
+Feel two first (full six-pattern grid in the fold below):
```text
- task ──► ● ● ● ● ══barrier══► synthesize
+ Fanout task ──► ● ● ● ● ══barrier══► synthesize
+ Adversarial worker ──► verifier×N → keep what still stands
```
-**Adversarial Verification** — the fox must not grade the henhouse. A worker produces; independent verifiers try to knock it down; only survivors remain.
-
-```text
- worker ──► verifier
- ├──► verifier
- └──► verifier → keep what still stands
-```
-
-**Generate-And-Filter** — you need options, not the first clever-sounding idea. Many generators, then a rubric (and dedupe).
-
-The same toolbox holds **Classify-And-Act** (route to a specialist), **Tournament** (pairwise judges to a winner), and **Loop Until Done** (keep spawning while “new findings?” is yes, with a hard `budget`). Borrow a style only when its cost buys clarity or safety.
-
-
-How each pattern maps to this lesson’s primitives
-
-| Pattern | Primitive sketch | Skip when… |
-|---------|------------------|------------|
-| Classify-And-Act | `agent` → branch → `agent` | Every item needs the same treatment |
-| Fanout-And-Synthesize | `pipeline` / `parallel` → merge | A single pass already fits |
-| Adversarial Verification | produce → `parallel(verify)` → filter | A wrong answer is cheap |
-| Generate-And-Filter | `parallel(gens)` → filter | The answer space is already tiny |
-| Tournament | pairwise judge `agent`s | A clear rubric picks a winner in one pass |
-| Loop Until Done | `while` + stop + `budget` | The work has a known size |
-
-```python
-# teaching sketch — classify then act
-kind = await ctx.agent("classify this ticket", schema=KIND)
-if kind["type"] == "billing":
- return await ctx.agent("handle billing…")
-```
-
-Compositions are normal: deep research often stacks fanout → filter → verify → synthesize.
-
-
-
-### When workflows meet untrusted input
-
-Support tickets and user feedback are untrusted. The agent that *reads* them should not also hold the keys that open a PR. Keep an airlock: readers stay read-only, pass only a structured summary; a trusted actor acts on the summary — never the raw text.
-
-```text
- backlog (untrusted)
- │
- ▼
- ┌─ QUARANTINE (read-only) ─┐
- │ readers → dedupe → summary │
- └────────────┬───────────────┘
- ▼
- ┌─ TRUSTED (high privilege) ─┐
- │ actor → fix / escalate │
- └─────────────────────────────┘
-```
-
-
-Official quarantine figure
-
-
-
-*Readers classify and dedupe in quarantine; high-privilege tools live on the trusted side. Pair with `/loop` if the backlog never sleeps.*
-
-
-
-## Walking `review-changes` — a composition
-
-The sample is not “one pattern.” It is **Fanout-And-Synthesize** with **Adversarial Verification** inside — and a light filter when only `isReal` findings survive.
+Sample `review-changes` = **Fanout** with **Adversarial** inside: `pipeline(audit, verify)` per dimension; `parallel` verifiers; keep only `isReal`.
```text
correctness ── audit ── verify ──┐
security ── audit ── verify ──┤── confirmed
performance ── audit ── verify ──┤
style ── audit ── verify ──┘
- fanout ▲ synthesize
- └── skeptical verify per finding
```
-`pipeline(DIMENSIONS, audit, verify)` gives each dimension its own desk. Inside `verify`, `parallel` of verifier agents is the adversarial chord. List filtering is the synthesize step. Phases mark Review → Verify; the journal remembers every `agent()` so a pause does not redo the audits.
-
-You can almost feel the three failure modes losing their seats: the fleet cannot stop after two dimensions, the author is not the judge, and the topology does not drift mid-run.
-
```python
-# from code.py — runnable sample (abbreviated)
+# 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"]]
- ctx.log(f"confirmed {len(confirmed)} real finding(s)")
return {"confirmed": confirmed}
```
+The fleet cannot stop early, the author is not the judge, and topology is not rewritten every chat turn.
+
-How this hangs on s15 (without replacing it)
+Six-pattern grid + primitive map
-s15 is still the host loop. s16 only adds a `Workflow` tool. You (or the model) ask for a saved name; the adapter runs the script.
+
-In the product, the run can sit in the background with notifications. Our teaching CLI keeps `demo` / `resume` in the foreground so phases and cache hits are easy to watch. Same ideas; we say so when we simplify.
+| 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 `agent`s | A clear rubric picks a winner |
+| Loop Until Done | `while` + stop + `budget` | Work size is known |
+
+```python
+# teaching sketch
+kind = await ctx.agent("classify this ticket", schema=KIND)
+if kind["type"] == "billing":
+ return await ctx.agent("handle billing…")
+```
-## Turning the gem: who holds the plan?
+
+Untrusted input: quarantine
-The useful question is not “how many agents?” but **who owns the topology**, and where the half-finished bowls live.
+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.
-| Neighbor | Who holds the plan | Where intermediates live | Best for |
-|----------|--------------------|--------------------------|----------|
-| [s06 Subagent](../s06_subagent/) | Model, one-shot | Mostly discarded | One dirty subtask |
-| [s13 Agent Teams](../s13_agent_teams/) | Lead + mailbox | Shared tasks / messages | Long-running peers |
-| [s15 Integrated Harness](../s15_integrated_harness/) | Model in one loop | `messages[]` | Cumulative coding agent |
-| **s16 Workflow** | **Script** | **Variables + journal** | Structured fan-out + verify |
-| [s17 Goal Loop](../s17_goal_loop/) | Evaluator at stop | Conversation as evidence | “Is the whole goal done?” |
+```text
+ backlog (untrusted) → [quarantine: readers → dedupe → summary] → [trusted: actor]
+```
-Cheaper paths still win often: a skill as a soft plan, a short multi-agent chat, a hand-written static orchestrator, or one larger model turn. Reach for a workflow when structure must outlast a single context — not because a panel sounds impressive.
+
-## And when to leave it on the shelf
+*High-privilege tools stay on the trusted side. Pair with `/loop` if the backlog never sleeps.*
-Workflows spend tokens and coordination. Most ordinary coding does not need five reviewers.
+
-Ask whether the job truly wants more compute and a custom harness. If a normal s15 turn — or one honest s06 subagent — will do, stop there. Restraint is part of the design thought.
+
+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
@@ -266,10 +177,10 @@ python s16_workflow_runtime/code.py demo # fixed fixture; watch phases
python s16_workflow_runtime/code.py resume # same runId; expect cache hits
```
-Watch Review give way to Verify. On a full resume, agents flip to `cached` and you should see `agents=0 tokens=0` — the notebook saying nothing needed reheating.
+A full resume should show `agents=0 tokens=0`.
## Next
-s16 is how a batch runs. [s17 Goal Loop](../s17_goal_loop/) asks a different question at the door: should we stop, or take another turn?
+s16 is how a batch runs. [s17 Goal Loop](../s17_goal_loop/) asks: stop, or take another turn?
-
+
diff --git a/s16_workflow_runtime/README.zh.md b/s16_workflow_runtime/README.zh.md
index 467a851f..e5c0974e 100644
--- a/s16_workflow_runtime/README.zh.md
+++ b/s16_workflow_runtime/README.zh.md
@@ -4,113 +4,78 @@
s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](../s17_goal_loop/)
-> *“一轮轮聊天,像每隔十秒给厨师发一条短信。Workflow 是厨房能照着做的菜谱。”*
+> Workflow = 写进代码的编排。脚本管拓扑,模型管每一步判断。
>
-> **Harness 层**: 编排 — 单 agent 循环之上,再跑一套多 agent 脚本。
+> **Harness 层**: 编排 — 单 agent 循环之上再跑多 agent 脚本。
>
-> 信任模型,工程化 harness。Workflow,就是把这句话往上提一层。
+> 信任模型,工程化 harness。Workflow 把这句话往上提一层。
---
-想象你跟朋友用微信一起做饭。“先切洋葱。”等回音。“切好了吗?”然后热锅、放盐。一道菜还能撑住这种节奏;二十桌宴席就不行了——步骤会丢,话会重复,手机一死还得从头来。
+## 问题
-模型既当厨师又当记事本时,感觉就是这样:计划与动手挤在同一段对话里。**Workflow** 是写好的菜谱。厨房(一个小 runtime)按谱做,帮手(子 agent)负责尝和判断,半成品放在台面上的碗里——变量和 journal——而不是塞进群聊。
+长任务里,计划和动手挤在同一段 chat:做到一半就宣布完工、自己批改自己偏甜、压缩几轮后约束悄悄丢了。并行、稳定结果形状、崩了续跑——软对话记忆扛不住。
-## 为什么还要另一层 harness?
+一轮轮催进度,像每隔十秒给厨师发短信。**Workflow** 是厨房能照着做的菜谱。
-默认的 Claude Code harness 已经很擅长“写代码那种形状”的活:改一点、跑一下、看报错、再试。一个循环。一颗脑袋。能做出不少工艺。
+## 想法
-可有些活需要**叠一层定制 harness**——深度调研、安全排查、agent teams、要铺开审查一整片改动。你可以事先用 SDK 手写那一层;也可以——这才是有意思的地方——让 Claude **为这次任务**起草一个 harness,跑起来,好用的再留下来。
+帮手(子 agent)仍负责想;**脚本**管循环、分发、合并。中间结果进变量和 journal,不进对话。
-课程那句口号往上提一层:每一步里信任模型;步骤怎么排,由你来定结构。
-
-## 长对话里你会看见的走偏
-
-从 s01 到 s15,计划与执行共享同一个上下文。下一步取决于刚才的发现时,这很舒服。可一旦任务变长、要大规模并行、结构又死板,或需要一个挑剔的第二意见,它就会发脆。
-
-耐心看一段很长的聊天,你会在学会术语之前先撞见熟面孔。做到五十项里的三十五就宣布完工。让它批改自己的作业,分数总是偏甜——狐狸给鸡窝打分。多轮对话和压缩过后,那句轻轻的“别动 X”渐渐听不见了。
-
-这些就是 agentic laziness、self-preferential bias、goal drift。名字不如感觉重要:同一个窗口既要干活,又要记住计划。软软的对话记忆,很难扛住并行、稳定的结果形状,以及崩了还能续上。
-
-## 点子落下的那一下
-
-假如计划住在代码里呢?
-
-帮手仍然负责想——每人一张干净桌子。**脚本**掌管循环、分发和合并。中间结果待在变量和 journal 里,不进对话。想偷懒提前收工的习惯,更难叫停整支队伍;自我检查的偏心,会撞上一个不是作者本人的第二帮手;漂移也难下手,因为拓扑不再由一个疲倦的叙述者每轮改写。
-
-**Workflow 把编排从「智力」挪到「结构」。** 模型仍在每次 `agent()` 里做判断;地图归脚本管。
+**编排从「智力」挪到「结构」。**
```text
- messages[] ──► Workflow(...) ──► tool_result { launched, result, task }
+ messages[] ──► Workflow(...) ──► tool_result
│
▼
- ┌───────────────┐
- │ 脚本掌管拓扑 │
- └───────┬───────┘
- │ agent / parallel / pipeline
+ 脚本管拓扑:agent / parallel / pipeline
+ │
▼
变量 + journal
```
-一次 `Workflow` 工具调用启动这次运行。进度在旁边轻轻响;菜谱做完,一条工具结果回来。
+一次 `Workflow` 工具调用开跑;菜谱做完,一条结果回来。
-运行时总览图(可选)
+运行时总览图

-## 两扇门——门外还有个表亲
+## 两扇门
-Claude Code 对入口说得很直白。
+- **动态**:模型为*这次*任务写 JS 编排(`script` / `scriptPath`)。
+- **已保存**:好脚本进 `.claude/workflows/`,用 `name` + `args` 再调。
+- **静态**(门外表亲):SDK / `claude -p` 事先写好,偏通用。
-**动态**——模型为*这次*任务写一段编排用的 JavaScript(`script`,之后可改 `scriptPath`)。问题还热着,就裁出一件合身的 harness。
+
-**已保存**——好脚本已经进了例如 `.claude/workflows/`。你用 `name` + `args` 再请它出来。一次值得留下的运行,沉淀成可复用的卡片。
+*左:固定流水线 → 泛报告。右:按你的代码现裁 → 具体建议。*
-门外还有表亲:**静态** harness,用 Agent SDK 或 `claude -p` 事先写好。它们得扛住所有边角,所以往往更泛。动态的是为这块布现裁的;合身了再存。
-
-
-
-*同一个问题,两套 harness。左边:固定的搜索→验证→摘要,终点是泛泛的报告。右边:读你的 billing 代码、分叉、请来魔鬼代言人,最后给出具体建议。*
-
-**这一章是 Python 教学运行时。** 同样的想法,每行都能读。演示按名字挂了一个已保存的 workflow;概念和 Claude Code 的脚本世界一一对应。我们不会再说“模型不能提交可执行代码”——那从来不是 Claude Code 的真相。这里只是不嵌入 JS 解释器。
+本章是 **Python 教学 runtime**(不嵌 JS VM)。概念对齐 Claude Code;演示走「已保存」门。模型在产品里本来就能交可执行脚本——我们只是不在这里跑 JS。
```python
-# 教学示意 — 已保存这扇门(不是完整 Claude Code schema)
+# 教学示意 — 不是完整 schema
Workflow({ "name": "review-changes", "args": { "changes": "..." } })
-
# Claude Code 还接受:script | scriptPath | resumeFromRunId
```
-## 脚本会说的三个动词
-
-学校义卖。每张桌子:搅拌 → 烘烤 → 装箱。帮手负责尝;菜谱决定先后。
+## 三个动词
```text
- agent 一个帮手,一件事
- pipeline 每块蛋糕自己走完各阶段 (默认 — 不等齐)
- parallel 等所有托盘都回来再往下 (屏障 — 少用)
+ agent 一个帮手,一件事(可带 schema → 校验 JSON)
+ pipeline 每个 item 自己走阶段(默认,不等齐)
+ parallel 等齐再往下(屏障,少用)
```
-`agent(prompt, opts?)` 请一个帮手。带上 `schema`,答案变成校验过的 JSON——下一阶段接得住的接口——第一次不对还给一次重试。
+失败时舰队继续:`parallel` 槽位变 `null`;`pipeline` 丢掉那个 item 及其后续 stage。合并前先过滤。
-`pipeline` 让蛋糕 A 装箱时,蛋糕 B 还可以在搅拌。`parallel` 只在下一步真的需要全部结果时才值得——比如尝完所有托盘再写评分表。
-
-```python
-# 教学示意 — 只看形状(可运行样本在 code.py)
-results = await ctx.pipeline(DIMENSIONS, audit, verify)
-confirmed = [f for r in results if r for f in r["confirmed"]]
-```
-
-帮手失手时,舰队仍然温和:`parallel` 的失败在该槽位变成 `null`;`pipeline` 的失败会丢掉**那个 item** 并跳过后续 stage。合并前先过滤。
-
-厨房暂停了呢?磁盘上的 journal 按**召唤顺序**记着每次调用。续跑回放**最长未改前缀**;碰到第一个改动,之后全部实跑。真正的 JS 运行时禁止 `Date.now()` / `Math.random()`,好让笔记本对得齐。这个 Python 演示不会完整沙箱那些——脚本仍写成确定性的吧。
+续跑:journal 按召唤顺序记;回放**最长未改前缀**,第一个改动之后全实跑。真 JS 运行时禁 `Date.now()` / `Math.random()`;本 demo 不完整沙箱——脚本仍写成确定性的。
```text
- journal [A] [B] [C] [D]
- 续跑 命中 命中 ✂ 实跑 ← 前缀在 C 断开
+ journal [A] [B] [C] [D]
+ 续跑 命中 命中 ✂ 实跑
```
@@ -118,144 +83,91 @@ confirmed = [f for r in results if r for f in r["confirmed"]]

-*官方卡片:`agent`,以及 `parallel`(屏障)与 `pipeline`(流式阶段)。Claude Code 还有 `model` / `isolation` / `agentType`;教学运行时把表面收小一点。*
+*`agent`;`parallel`(屏障)vs `pipeline`(流式阶段)。Claude Code 还有 `model` / `isolation` / `agentType`;教学面更小。*
-更轻的动词:`phase`、`log`、嵌一层 `workflow`、`args`、`budget`。
+更轻:`phase`、`log`、嵌一层 `workflow`、`args`、`budget`。
-## 会写菜谱之后——模式工具箱
+## 两种形状 + 一个样本
-动词是面粉和火候。人们反复发明的,是少数几种*形状*——工具箱,不是必点菜单。
-
-
-
-*官方六模式网格。脚本掌管拓扑;本课用 `agent` / `parallel` / `pipeline` / journal 把每种形状说出来。*
-
-对后面的示例,先摸清三种最要紧的形状——名字可以后到。
-
-**Fanout-And-Synthesize(分发再汇总)**——五十个文件塞不进一个疲倦的上下文。拆开、多跑、在屏障处合并。
+先摸两种(完整六模式见下方折叠):
```text
- task ──► ● ● ● ● ══屏障══► synthesize
+ Fanout task ──► ● ● ● ● ══屏障══► synthesize
+ Adversarial worker ──► verifier×N → 只留站得住的
```
-**Adversarial Verification(对抗验证)**——狐狸不该给鸡窝打分。工人产出;独立验证者来挑刺;只留下还站得住的。
-
-```text
- worker ──► verifier
- ├──► verifier
- └──► verifier → 留下仍然成立的
-```
-
-**Generate-And-Filter(生成再过滤)**——你要的是选项,不是第一个听起来机灵的念头。许多生成器,再加一把量尺(和去重)。
-
-同一工具箱里还有 **Classify-And-Act**(路由到专家)、**Tournament**(两两比较出冠军)、**Loop Until Done**(“还有新发现?”为是就继续派,并加上硬性 `budget`)。只有额外成本能买到更清楚或更稳妥的结果时,才去借一种风格。
-
-
-每种模式如何落到本课原语
-
-| 模式 | 原语速写 | 什么时候别用 |
-|------|----------|--------------|
-| Classify-And-Act | `agent` → 分支 → `agent` | 每件东西其实都该同样处理 |
-| Fanout-And-Synthesize | `pipeline` / `parallel` → 合并 | 一趟已经装得下 |
-| Adversarial Verification | 产出 → `parallel(verify)` → 过滤 | 答错很便宜 |
-| Generate-And-Filter | `parallel(gens)` → 过滤 | 好答案空间本来就很小 |
-| Tournament | 两两裁判 `agent` | 清晰量尺一趟就能选出赢家 |
-| Loop Until Done | `while` + 停止 + `budget` | 工作量已知 |
-
-```python
-# 教学示意 — 先分类再行动
-kind = await ctx.agent("给这张工单分类", schema=KIND)
-if kind["type"] == "billing":
- return await ctx.agent("处理账单…")
-```
-
-组合是常态:深度调研常常叠成 分发 → 过滤 → 验证 → 汇总。
-
-
-
-### 当 workflow 碰上不可信输入
-
-工单和用户反馈是不可信的。*读*它们的 agent,不该同时握着能开 PR 的钥匙。留一道气闸:读者只读,只递结构化摘要;受信任的 actor 根据摘要行动——从不碰原始正文。
-
-```text
- 积压(不可信)
- │
- ▼
- ┌─ 隔离区(只读) ────────┐
- │ readers → 去重 → 摘要 │
- └────────────┬────────────┘
- ▼
- ┌─ 受信任(高权限) ──────┐
- │ actor → 修复 / 升级人工 │
- └─────────────────────────┘
-```
-
-
-官方隔离分流图
-
-
-
-*读者在隔离区里分类、去重;高权限工具住在受信任一侧。积压永远睡不着时,可以和 `/loop` 配对。*
-
-
-
-## 跟着 `review-changes` 走一圈——一种组合
-
-示例不是“一种模式”。它是 **Fanout-And-Synthesize**,里面嵌着 **Adversarial Verification**——结尾再轻轻过滤,只留下 `isReal` 的 finding。
+样本 `review-changes` = **Fanout** 里嵌 **Adversarial**:多维度 `pipeline(audit, verify)`,`verify` 里 `parallel` 挑刺,过滤后只留 `isReal`。
```text
correctness ── 审计 ── 验证 ──┐
- security ── 审计 ── 验证 ──┤── 确认列表
+ security ── 审计 ── 验证 ──┤── confirmed
performance ── 审计 ── 验证 ──┤
style ── 审计 ── 验证 ──┘
- 分发 ▲ 汇总
- └── 每条 finding 的怀疑式验证
```
-`pipeline(DIMENSIONS, audit, verify)` 给每个维度自己的桌子。`verify` 里对验证 agent 做 `parallel`,就是对抗那一和弦。列表过滤是汇总。`phase` 标出 Review → Verify;journal 记住每次 `agent()`,暂停也不会重做审计。
-
-那三种走偏,会感觉自己最爱的座位被撤了:舰队不能在两个维度后收工,作者不当裁判,拓扑也不会在中途漂移。
-
```python
-# 来自 code.py — 可运行样本(节选)
+# 来自 code.py(节选)
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"]]
- ctx.log(f"确认了 {len(confirmed)} 个真实问题")
return {"confirmed": confirmed}
```
+舰队不能早停、作者不当裁判、拓扑不靠 chat 每轮改写。
+
-怎样挂在 s15 上(却不取代它)
+六种模式网格 + 原语对照
-s15 仍是宿主循环。s16 只多了一个 `Workflow` 工具。你(或模型)报一个已保存的名字;适配器跑脚本。
+
-在产品里,这次运行可以待在后台、带着通知。教学 CLI 把 `demo` / `resume` 放在前台,好让阶段和缓存命中容易看见。想法相同;简化之处我们会明说。
+| 模式 | 原语速写 | 什么时候别用 |
+|------|----------|--------------|
+| Classify-And-Act | `agent` → 分支 → `agent` | 每件都该同样处理 |
+| Fanout-And-Synthesize | `pipeline` / `parallel` → 合并 | 一趟已装得下 |
+| Adversarial Verification | 产出 → `parallel(verify)` → 过滤 | 答错很便宜 |
+| Generate-And-Filter | `parallel(gens)` → 过滤 | 答案空间本来就小 |
+| Tournament | 两两裁判 `agent` | 清晰量尺一趟能选 |
+| Loop Until Done | `while` + 停止 + `budget` | 工作量已知 |
+
+```python
+# 教学示意
+kind = await ctx.agent("给工单分类", schema=KIND)
+if kind["type"] == "billing":
+ return await ctx.agent("处理账单…")
+```
-## 转一转这颗宝石:谁握着计划?
+
+不可信输入:隔离分流(quarantine)
-有用的问题不是“几个 agent?”,而是**谁拥有拓扑**,半成品的碗放在哪。
+读工单的 agent 不该同时握开 PR 的钥匙。读者只读 → 结构化摘要;受信任 actor 只看摘要行动。
-| 邻居 | 谁握着计划 | 中间结果住哪 | 最适合 |
-|------|------------|--------------|--------|
-| [s06 子 Agent](../s06_subagent/) | 模型,一次性 | 多半丢掉 | 隔离一个脏的子任务 |
-| [s13 Agent Teams](../s13_agent_teams/) | Lead + 邮箱 | 共享任务 / 消息 | 长跑的同伴 |
-| [s15 Agent Harness 集成](../s15_integrated_harness/) | 模型在一个循环里 | `messages[]` | 累积型 coding agent |
-| **s16 Workflow** | **脚本** | **变量 + journal** | 结构化分发与验证 |
-| [s17 Goal Loop](../s17_goal_loop/) | 停止时的判断器 | 对话当证据 | “整个目标做完了吗?” |
+```text
+ 积压(不可信)→ [隔离区: readers → 去重 → 摘要] → [受信任: actor]
+```
-更便宜的路经常就够:skill 当软计划、一小段多 agent 闲聊、手写静态编排,或更大的单轮模型调用。当结构必须比单个上下文活得更久,再伸手去拿 workflow——不是因为“专家团”听起来很酷。
+
-## 什么时候先放回架子上
+*高权限工具住在受信任一侧。积压睡不着时可配 `/loop`。*
-Workflow 要花 token,也有协调成本。大多数普通写代码,并不需要五人评审团。
+
-问问这活是否真的想要更多算力和一层定制 harness。若普通的 s15 一轮——或一个老实的 s06 子 agent——就够,就停在那儿。克制也是设计思想的一部分。
+
+怎样挂在 s15 上
+
+s15 仍是宿主循环;s16 只多一个 `Workflow` 工具。产品里可后台跑;教学 CLI 用前台 `demo` / `resume` 看阶段和缓存。
+
+
+
+## 邻居 & 何时别用
+
+谁握计划?s06 一次性委派、s13 邮箱同伴、s15 单循环、**s16 脚本 + journal**、s17 门口问「整目标做完了吗」。
+
+普通改代码:s15 一轮或一个 s06 往往够。Workflow 要 token 和协调——结构必须比单个上下文活得更久时再用。
## 试一下
@@ -265,10 +177,10 @@ python s16_workflow_runtime/code.py demo # 固定数据;看阶段
python s16_workflow_runtime/code.py resume # 同一 runId;期待缓存命中
```
-看 Review 让给 Verify。完整续跑时 agent 翻成 `cached`,并应看到 `agents=0 tokens=0`——笔记本在说:没有什么需要重新加热。
+完整续跑应看到 `agents=0 tokens=0`。
## 接下来
-s16 讲一批活怎么跑。[s17 Goal Loop](../s17_goal_loop/) 在门口问另一个问题:该停,还是再来一轮?
+s16 讲一批活怎么跑。[s17 Goal Loop](../s17_goal_loop/) 问:该停,还是再来一轮?
-
+