重點摘要
- 動手的 agent 只能一個(寫入單線程)。但同一個 agent 不可能從頭做到尾,工作數小時後注意力品質下降(context rot)。
- 解法不是換 agent,也不是加 agent,是讓「下一個 agent」能無痛接手。接力棒設計才是 multi-agent 工程的真正關鍵。
- Cycle file = file-as-state-machine:把每個 cycle 的完整狀態寫進一份 markdown,活在 git,跨 session 可讀,撐過對話 compaction。
- 8-stage 結構每個 stage 對應一個 multi-agent 容易踩到的坑:baseline 污染、ripple effect、vacuous test、groupthink。
- 5 種 cycle type,各有 stage profile。不是每個 cycle 都跑 8-stage,硬塞會浪費或漏。
- file-as-state-machine 不只 multi-agent 用得到。ADR、RFC、postmortem 都是這個 pattern,multi-agent workflow 把它的價值放大 100×。
- 新環境 bootstrap:4 個檔案 + 一段 prompt,就能在新電腦 / 新 Claude Code / Antigravity / Codex / Cursor / Aider 上啟動這套流程,不分工具。
本系列【進階篇】。提供完整 SOP 跟 4 個檔範本,假設你已經知道為什麼 multi-agent 工程需要 cycle file workflow。還沒看過為什麼?先讀 入門篇:「為什麼修不完?」— 從 21 輪迴圈到 5 type taxonomy 的多 agent 角色設計——用第一人稱故事告訴你 5 個 agent type 是怎麼從踩坑反推出來的,讀完再回來看這篇就會懂為什麼這 4 個檔長這樣。
Multi-agent 工作流有個業界共識的硬約束:同時間只能有一個 agent 動手寫(寫 code / 寫 spec / 寫 migration)。多個 agent 平行寫產生隱性風格 + 決策衝突,Cognition / Anthropic / Stanford 都從不同角度驗證過這條。
但這條約束衍生一個立刻撞上的問題:
寫入單線程沒錯,但一個 agent 怎麼跑一個多月的長期專案不撞 context rot?同一個 agent 從第一週寫到第六週,中間累積的對話歷史不會把它壓垮嗎?
答:不是「一個 agent 跑到底」,是「每個 cycle 換新 agent,cycle file 接力」。
這篇講 cycle file 設計方法論——為什麼必須是檔案不是對話、為什麼必須在 git 不能在 Notion、8-stage 結構每個 stage 對應哪個 multi-agent 踩坑,以及這個 pattern 怎麼推廣到 ADR / RFC / postmortem 這類非 multi-agent 場景。
對照組:傳統工業界 RD 開發流程
在進入 multi-agent cycle file 方法論之前,先把工業界標準的 RD 開發流程攤開——對照基準清楚了,後面的對應關係才好讀。本文不是發明新流程,是把這套經典 SDLC 對應到能跑在多個 AI agent 上的 cycle file 結構。
經典流程九步
- PM 整理需求 — business requirement,decide what to build
- SA 分析需求(可由 PM 兼任)— 系統分析,what the system must do
- SD 設計需求(可由 PM 兼任)— 系統設計,how the system should do it
- RD 撰寫程式 — implementation
- RD 自測後交付 — pre-PR self-test
- QA 進行測試,建立錯誤表 — finding list,QA 只報事實不下 P0/P1
- PM 確認錯誤表,跟 SPEC 比對 — triage:是 bug 還是 feature 還是 usage 還是 not_issue
- 交給 RD 修正 → 修正後再給 QA → PM,持續 loop — 直到 PM 點頭。這個 loop 是品質的核心,不是 bug,是設計
- 上到 GA 區,以正式資料進行測試 — production smoke,真實數據才能發現假性綠燈
測試分三段——這三段不能混
| 類型 | 內容 | 在 cycle file 對應 |
|---|---|---|
| 測試程式 | unit test / integration test / E2E test scripts | Stage 5a failing test + Stage 5c regression suite |
| 測試環境 | staging server / sandbox / test docker compose / backend services | Stage 0.5 Pre-cycle hygiene 確認所有服務 up |
| 測試資料 | fixture / seed data / disposable test users / canonical baseline | Stage 0.5 fixture reset + disposable qa_* fixtures |
經典流程 ↔ Cycle file 對應
| 傳統 RD 流程 | Cycle file 對應 stage |
|---|---|
| PM 整理需求 | Cycle file Header 的 spec section + related INV |
| SA / SD 分析設計 | Spec.md + invariants.md 條目(契約寫死) |
| RD 撰寫 + 自測 | Stage 1 RD 自測(單線程,一個 agent 動手) |
| QA 測試 + 錯誤表 | Stage 2 QA wave 並行 + Stage 3 OPEN findings |
| PM 確認比對 SPEC | Stage 4 PM triage(bug / feature / usage / not_issue) |
| RD 修正 → QA → PM loop | Stage 5 fix → Stage 6 regression → Stage 7 comparison QA → 回 Stage 3 |
| PM 點頭 | Stage 8 merge gate(全綠才合) |
| 上 GA 區正式資料測試 | Production smoke + user smoke(primary detection,觸發 T-user-smoke-followup cycle) |
關鍵差別:傳統流程角色是「人」(PM / SA / SD / RD / QA),cycle file workflow 把這些角色變成「agent 在不同 stage 的職責」——同一個 LLM agent 在 Stage 1 是 RD,在 Stage 2 wave 之中扮演 QA(但 scope 鎖死),Stage 7 是 comparison QA。PM 永遠是人,因為「跟 SPEC 比對 + 做價值判斷」這層 LLM 不該越界。
§1 為什麼「對話 context」是錯誤的狀態載體
多數人用 Claude / GPT / Cursor / Aider 寫 code 的時候,默認狀態活在對話裡——上一句問題、AI 上一個回應、再上一個截圖,都在 chat history 裡。看起來理所當然,直到撞到三個事實:
- 對話會壓縮(compaction)。主流工具在 context 接近上限時都會自動壓縮歷史。「我剛剛跟你說過 X」這句話,壓縮一輪後就變成「我們討論過某些事」。具體細節進了 summary,但 summary 本身會再被壓縮。資訊密度持續下降。
- 對話只活在單一 session。開新 session = 全新對話,讀不到上次的 context。即使有 memory file(persistent profile / preferences),那是「人格 / 偏好」層,不是「這個專案這個 PR 跑到哪了」的狀態。
- 對話沒 git history。半年後翻回去看「為什麼這個 PR merge」,翻 chat log 是不可能任務——對話沒 commit message、沒 tag、沒 diff,review 工具完全用不上。
傳統 workaround 是「我把上下文 paste 進新 session」。這是 fragile 的——你會漏、你會省略、你會把 600 字濃縮成 30 字然後新 session 推不出原本的決策邏輯。
結論:對話狀態必然會掉,任何長期 multi-agent workflow 都要把 state 寫到對話以外的地方。Cycle file 是其中一種具體實踐。
§2 Cycle File 的核心思想:file-as-state-machine
一個 cycle file = 一個 PR cycle 的完整狀態機。離散的 stage 有明確 entry / exit 條件,跨 session 接手 = 讀檔不是讀對話。
為什麼必須是 markdown 不是 JSON / DB
- Human-AI 雙方都能讀。人要看,AI 要讀,PR reviewer 也要看。Markdown 是最低共通格式。
- Diff 友善。Stage 3 加一個 finding,git diff 看得清清楚楚。JSON 一改整個檔重排,DB 改一個 row 沒 diff。
- 離 code 近。
docs/cycles/Cn-*.md跟 source code 在同一個 repo,branch 切換時 cycle file 也跟著切換。
為什麼必須在 git 不能在 Notion / Confluence
- Audit trail。每次 cycle file update 都是一個 commit,who / when / why 一目了然。Cloud doc 改了就改了,沒人記得是誰改的。
- 跟 code 同生死。Branch 跟 cycle file 綁在一起,rebase / cherry-pick / revert 都會帶走 cycle file。Notion 不知道 code 在哪個 branch。
- 跨工具不依賴。Cloud doc 服務掛了 cycle file 就讀不到。Git 不會掛——而且即使原 repo 沒了,每個 clone 都有完整歷史。
§3 8-stage 結構——每個 stage 對應一個 multi-agent 踩坑
本節拆 cycle file 8-stage 的標準結構,標出每個 stage 對應哪個 multi-agent 容易撞的坑。
Header — cycle 身分證
# Cycle Cn — <short PR title>
Owner: <engineer agent / human>
Started: YYYY-MM-DD HH:MM
Status: open / in_qa / in_triage / in_fix / regression / closed
Cycle Type: T-PR-cycle / T-regression-fix / T-feature-cycle /
T-spec-audit / T-user-smoke-followup / T-mutation-test
Related:
- PR / branch: <commit_sha>
- Spec section: <§X.Y>
- Primary INV(s) targeted: INV-XXX-NNN
下個 agent 接手第一件事是讀 Header。Cycle Type 決定哪些 stage 必經、哪些 N/A——不分 type 把所有 cycle 都當 PR-cycle 跑,結果 regression-fix 跑 8-stage 浪費,user-smoke-followup 跑 8-stage 又錯位(user 已經是 primary detection 了,還跑 QA wave 是反過來)。
Stage 0.5 — Pre-cycle hygiene
git status --shortclean(除了本 cycle 將動的 file)- HEAD = <commit-sha>,不是 mid-rebase / mid-merge state
- seed / fixture reset script 跑過,fixture 為 canonical
- 列出本 cycle 將建立的 disposable test fixtures,不複用共享 fixture
- 所有相關服務 healthy(backend / proxy / DB / storage 皆 up)
對應的坑:跨 cycle 副作用會讓新 cycle 在污染狀態跑出 false positive ✅。上輪 cycle 殘留的 test payload、未清的 disabled user、過期的 rate-limit lockout——新 agent 進場已經在污染狀態,QA wave 跑出來的綠燈是 false confidence。Pre-cycle baseline check 是唯一的事前防線。
Stage 1: RD 自測
- 單元測試全綠(附 commit SHA)
- Live smoke:對 endpoint X / user Y 跑 happy path(寫一兩行紀錄)
- PR header 完整(INV 宣告 / QA scope / Verification 三段)
RD 在開 PR 之前就先過自己的關。沒過自測的 PR 連 Stage 2 都進不去——直接退回。
Stage 2: QA wave(並行讀取)
2-4 個 QA agent 並行,每個 scope 鎖死 1-3 個 invariant。這是 multi-agent「平行覆蓋」的核心場景——讀取不衝突。
QA agent A — INV-XXX-NNN red-team
QA agent B — INV-YYY-MMM regression
QA agent C (optional) — same scope as A, no knowledge of A's findings
(consistency check; 結果一致則 spec 寫得清楚,
不一致則 spec 有歧義先收斂)
QA agent 只能標 ✅ / ❌ / OPEN,絕對不准標 P0/P1——那是 PM 的 authority。OPEN 一律往 PM triage 走。
Stage 3: OPEN findings(等 PM triage)
所有 QA agent 的 OPEN finding 收進一張 finding table。Finding 格式:
### Finding F-Cn-001
- QA agent: A
- Resolver/Feature: <name>
- Observed: <事實>
- Repro: <exact commands>
- PM triage:
- Class: bug / feature / usage / not_issue / spec_clarification
- Confidence: high / low
- Reasoning: <≤2 sentences citing spec/INV>
- User review needed: yes / no
Findings ≥3 時派 PM-agent 跑 first-pass triage,user 只 review confidence=low 與 class=spec_clarification 兩類。Findings ≤2 user 直接判,省 round-trip。
Stage 4: User review(只看 low-conf)
User 對每個 confidence=low 或 spec_clarification 項目走 PM triage 分判,30 秒一個 finding。超過 2 分鐘 = finding 太大,要拆。
Downstream sweep(Stage 5 之前必填)
本 cycle 改動的 state(DB tables / schema / role-cap definition / fixture state),列出有哪些其他 resolver / query 會讀到。grep 全 repo 找 reader,寧可 false positive 多列幾條,少列就漏 ripple。
對應的坑:改動會 ripple 到 cycle scope 外的 readers,沒 explicit list 必漏。經典場景:Cycle A 改了 fixture seed script,衍生 1 小時後 user 點 dashboard 某個 tab 崩。原因是 Cycle A 改了某張表的 state,影響到 cycle scope 外的另一個 resolver——那個 resolver 不在 Cycle A 的測試範圍裡,沒人提醒去看,bug 就溜進去。Downstream sweep 強制 RD 在 Stage 5 開修前 explicitly list ripple 範圍,Stage 6 regression 必須 cover。
Stage 5: RD fix(TDD red-green 拆 5a / 5b / 5c)
Stage 5a — write failing test
- 寫 test 對應 invariant / 對應 finding attack scenario
- 跑 test → 預期 ❌ red(沒紅 = test 寫錯)
- commit "test: failing test for F-Cn-NNN / INV-XXX-NNN (red)"
Stage 5b — implement fix
- 寫 fix
- 重跑 5a 的 test → 預期 ✅ green
- commit "fix: ... (green via test in <5a-sha>)"
- commit message 必填 "Failing test verified at: <5a-sha>"
Stage 5c — refactor + regression
- refactor 必要時
- 跑全套既有 test 確認無 regression
對應的坑:「test + fix 同 commit」沒驗 test 真的會抓對應 bug,可能是 vacuous test(永遠 pass 但不 cover 要 cover 的 case)。沒有「test 先 ❌、fix 後 ✅」這個 TDD 基本動作,你不知道 test 是真的在驗還是空跑。拆三個 commit 的好處是 bisect 看得出 red→green 軌跡。
Stage 6: Regression
Stage 5 fix 跑完,QA agent 重跑 Stage 2 的 wave(同樣的 prompt,只是 commit SHA 換成 fix sha)。Downstream sweep 列出的 ripple 範圍必須驗。
Stage 7: Comparison QA(對抗 groupthink)
派一個全新的 QA agent(不告訴它原 QA 抓到什麼),跑同一份 PR。如果它抓出新 finding = 原 QA 還有盲點。如果它跟原 QA 結論一致 = 確認可信。
對應的坑:QA agent + Engineer agent 同 LLM 譜系,想得到的 attack scenario 高度重疊,共有盲點。Comparison QA 是減輕 groupthink 的最低成本做法——成本是多派一個 agent,收穫是另一個視角的覆蓋。
Stage 8: Merge gate
要合 PR,全部都要打勾:
- PR header 完整(INV 宣告 / QA scope / Verification)
- 宣告的「滿足」invariant:兩個 QA agent 都報 ✅
- 宣告的「可能影響」invariant:回歸都 ✅
- 兩個 QA agent 報告結論一致
- OPEN list 清空(全部 triage 完)
- 單元測試綠
- 如 PR 影響 UI → 手動 smoke 一次 happy path
Stage 8 全綠才 merge,cycle file commit 留檔,close cycle。
§4 Cycle Type — 5 種 stage profile,不是每個 cycle 都跑 8-stage
「Cycle Type」field 解決一個很實在的問題:不同性質的 cycle 用不同 stage profile,硬塞 8-stage 會浪費 stage 或漏 stage。
| Cycle Type | 觸發 | Stage profile |
|---|---|---|
T-PR-cycle |
開 PR 等 merge | 完整 8-stage(QA wave + regression + comparison newbie) |
T-regression-fix |
Engineer / agent 自抓 regression | 5-stage:skip Stage 2 QA wave + Stage 4 user review;root cause 在 cycle file 開頭講清 |
T-feature-cycle |
Forward-going 新 feature | Stage 5 在 Stage 2 之前(先實作再 QA wave 對 INV 驗證) |
T-spec-audit |
隨機抽樣 / category 全驗 | Stage 2 only + report;無 fix。Findings raise 為 OPEN 給 PM |
T-user-smoke-followup |
User 直接報 bug | Stage 3 直接收 finding(user 是 primary detection)+ skip Stage 2;後續 5/6/7/8 全跑 |
Cycle file 開頭強制填 Cycle Type: T-XXX,Stage 8 merge gate 只 enforce 該 type 必經的 stage。
§5 三個工程效益——為什麼這個設計值得
效益 1:撐過對話 compaction
對話被壓縮的時候,壓的是 chat history,不是 git artifact。下個 session 我打開 docs/cycles/Cn-*.md,完整的 persona、attack scenario、findings、PM triage 結果都還在。
對照組:如果這些資訊只活在對話裡,compaction 一輪 → 只剩「我們做了一些 QA」這種無資訊摘要 → 下個 agent 接手等於從零開始。
效益 2:跨 session / 跨 agent 可讀
新 agent invocation(無論是新 session、不同 agent、甚至不同人接手),讀檔就能上工。長期專案累積的 cycle 是獨立 Engineer invocation,每個 cycle 開頭讀 workflow SOP + invariants 契約 + 當前 cycle file 進度,3 分鐘進入狀況。
對照組:沒 cycle file 的話,新 agent 進場第一件事是「請告訴我前面跑到哪了」——你自己要把 600 行對話濃縮 paste 給它,中間漏東漏西。
效益 3:6 個月後的自己有 audit trail
半年後 grep 某條 invariant ID,找到這條 invariant 是哪個 cycle 加的、為什麼加、當時 PM 怎麼判的——全部在 git 裡,commit message 帶 finding ID。
對照組:Cloud doc 寫的 ADR、Confluence 寫的 design doc——半年後權限過期、url 換掉、search 找不到。
§6 推廣:file-as-state-machine 不只 multi-agent 用得到
Cycle file 的核心是 file-as-state-machine:把工程過程的 state 從「對話 / 會議 / 腦袋」搬到「檔案 / git」。這個 pattern 在傳統軟工不是新東西,只是名字不一樣。
| 名稱 | 用途 | 跟 cycle file 共同性質 |
|---|---|---|
| ADR(Architecture Decision Record) | 記錄架構決策的 context / 選項 / 決定 / 後果 | 活在 git,撐過人員流動,6 個月後可 audit |
| RFC(Request for Comments) | 大型 feature 的設計提案 + comment trail | 同上;增加 review 階段的離散 stage |
| Postmortem | incident 事後分析 + 行動項 | 同上;Stage 包含 timeline / root cause / action items |
| Cycle file | single PR 的完整 lifecycle | 同上;比 ADR/RFC 更短週期、更高頻次 |
共同性質:把工程過程的 state 從可揮發載體(對話、會議、腦袋)搬到不可揮發載體(git、版控檔案)。對 single-developer 也有用——你不會記得三個月前為什麼選 PostgreSQL 而不是 MySQL,但 ADR 會記得。
對 multi-agent 工作流,這個 pattern 的價值放大 100×。因為 multi-agent 有兩個額外的揮發源:
- 對話 compaction(每幾小時就一次)
- 跨 session / 跨 agent 切換(每個 cycle 一次)
Single-developer 的對話 context 一個專案可能撐幾天,multi-agent workflow 可能撐幾小時。Cycle file 的「狀態接力棒」價值在 multi-agent 場景才完整展現。
§7 在新環境啟動這套流程——4 個檔案 + 一段 bootstrap prompt
如果今天換新電腦、開新專案、或換工具(Claude Code → Antigravity / Codex / Cursor / Aider),怎麼快速把這套 cycle workflow 啟動到「下一個 agent 進來就能照跑」的狀態?答案是最小可行 kit:4 個檔案 + 一段給 agent 的開場白。
最小可行 kit:4 個檔案
| 檔案 | 內容 | 變動頻次 |
|---|---|---|
docs/workflow.md |
8-stage SOP 完整版(本文 §3 內容) | 每 retro 一次 amend |
docs/cycle-template.md |
Cycle file 結構 template(複製即可填) | 穩定,少改 |
docs/invariants.md |
所有 INV-XXX-NNN 契約列表(初始空白,隨 cycle 累積) | 每 cycle 可能 amend |
AGENTS.md |
Role taxonomy(perspective-driven,不是 8 職稱)+ 資源預算上限 | 穩定,專案改 tech stack 時才動 |
這 4 個檔不是「規劃文件」,是「執行契約」——每 PR 強制讀,違反退回。具體 staffing / per-cycle 進度寫在 docs/cycles/Cn-*.md。
4 個檔案的最小內容範本
下面 4 段是直接可複製貼到專案的 minimal 內容。Day-1 把這 4 個檔放進 docs/ 跟 root 之後,就有完整的 cycle workflow kit,新 agent 進來照走。
檔案 1/4 — docs/workflow.md
8-stage SOP 的 skeleton。詳細每個 stage 規則見本文 §3,這份 skeleton 是「每個 agent 開工前必讀」的最小契約版本。
# Workflow SOP — Cycle-based PR Pipeline
> 所有 PR 走 cycle file 流程。違反 stage 順序的 PR 直接退回。
## 8 Stages
| Stage | 動作 | 誰做 | 必經? |
|---|---|---|---|
| 0.5 | Pre-cycle hygiene (baseline 乾淨確認) | Writer | yes |
| 1 | RD 自測 (unit test + live smoke + PR header) | Writer | yes |
| 2 | QA wave (2-4 verifier 並行,每個 scope 鎖 1-3 INV) | Verifier(s) | yes (PR-cycle) |
| 3 | OPEN findings table (QA agent 收 finding) | Verifier | yes |
| 4 | PM triage (bug / feature / usage / not_issue 分判) | PM / Triage | yes |
| Downstream sweep | grep 列出 ripple 範圍 (本 cycle scope 外的 readers) | Writer | yes |
| 5 | RD fix — 5a 寫 failing test → 5b 寫 fix → 5c refactor | Writer | yes (有 bug 才跑) |
| 6 | Regression (重跑 Stage 2 wave,scope 含 ripple) | Verifier | yes |
| 7 | Comparison QA (新 agent 不知道原 QA 結果,re-audit) | Verifier | recommended |
| 8 | Merge gate (全綠才合) | Writer + PM | yes |
## 5 Cycle Types (決定哪些 stage 必經)
| Type | 觸發 | Stage profile |
|---|---|---|
| `T-PR-cycle` | 開 PR 等 merge | 完整 8-stage |
| `T-regression-fix` | engineer 自抓 regression | 5-stage:skip Stage 2 + Stage 4 |
| `T-feature-cycle` | forward-going 新 feature | Stage 5 在 Stage 2 之前 |
| `T-spec-audit` | 隨機抽樣 / category 全驗 | Stage 2 only + report (無 fix) |
| `T-user-smoke-followup` | user 報 bug | Stage 3 直接收 finding,skip Stage 2 |
## Iron Rules (執行契約,違反退回)
1. **寫入單線程**:同時間只能 1 個 Writer agent 動手。其他 agent 都不准動 code / spec / schema / migration。
2. **Verifier 不准標 P0/P1**:只能 ✅ / ❌ / OPEN。嚴重度是 Triage 的 authority。
3. **Verifier scope 鎖死 1-3 INV**:不准「找任何 bug」(R35 21 輪迴圈的反面教材)。
4. **TDD red-green 拆三 commit**:Stage 5a failing test red commit → 5b fix green commit (帶 `Failing test verified at: <5a-sha>`) → 5c refactor。`test+fix 同 commit` = 沒驗 test 有效。
5. **修了 bug 必須加 INV 到 `docs/invariants.md`**:沒加不算修完。半年後同類 bug 一定回來。
6. **cycle file 留檔不刪**:cycle 收完 commit 進 git,當作 audit trail。
7. **每月 retro amend workflow.md**:漏掉的 bug / 浪費的 stage / 卡住的 finding → 回頭改 SOP。
檔案 2/4 — docs/cycle-template.md
每個 cycle 開頭從這份複製出 docs/cycles/Cn-<topic>.md(n 是流水號,grep 看下一個)。照著填,不要自己改 stage 結構。
# Cycle Cn — <short PR title>
**Owner**: <agent ID / human>
**Started**: YYYY-MM-DD HH:MM
**Status**: open / in_qa / in_triage / in_fix / regression / closed
**Cycle Type**: T-PR-cycle / T-regression-fix / T-feature-cycle / T-spec-audit / T-user-smoke-followup
**Related**:
- PR / branch: <commit_sha or branch>
- Spec section: <§X.Y or "N/A">
- Primary INV(s) targeted: INV-XXX-NNN, INV-YYY-MMM
---
## Stage 0.5 — Pre-cycle hygiene
- [ ] `git status --short` clean (除了本 cycle 將動的 file)
- [ ] HEAD = <commit-sha>
- [ ] fixture reset 跑過, baseline canonical
- [ ] 列出本 cycle 用的 disposable fixtures (qa_<cycle>_<role>_<timestamp> prefix)
- [ ] 所有相關服務 healthy
## Stage 1: RD 自測
- [ ] unit test 全綠 (commit: <sha>)
- [ ] live smoke 紀錄:<endpoint X / user Y / happy path 結果>
- [ ] PR header 完整 (滿足 INV / 可能影響 INV / 提議新增 INV 三段)
## Stage 2: QA wave
### QA agent A — INV-XXX-NNN red-team
- Launched: HH:MM
- Result: ✅ / ❌ / OPEN
- Findings: <count>
### QA agent B — INV-YYY-MMM regression
- Launched: HH:MM
- Result: ✅ / ❌ / OPEN
## Stage 3: OPEN findings
### F-Cn-001
- QA agent: A
- Resolver/Feature: <name>
- Observed: <事實,不下判斷>
- Repro:
```
<exact commands / GraphQL / curl>
```
- PM triage:
- Class: bug / feature / usage / not_issue / spec_clarification
- Confidence: high / low
- Reasoning: <≤2 sentences citing spec/INV>
- User review needed: yes / no
(repeat for each finding)
## Stage 4: User review (only low-conf items)
- [ ] F-Cn-XXX user-confirmed class: <class>
## Downstream sweep (Stage 5 之前必填)
### 本 cycle 改動的 state
- DB tables: <list>
- Schema: <changes>
- Fixture state: <changes>
### 讀取上述 state 的其他 resolver / query
| State | Reader | Stage 6 必驗 |
|---|---|---|
| <table_X> | <Resolver A / Query B> | ✅ |
## Stage 5: RD fix
### Stage 5a — failing test (red)
- Test 檔: <path>
- 跑出 red: commit <5a-sha>
### Stage 5b — implement fix (green)
- Fix commit: <5b-sha> (帶 `Failing test verified at: <5a-sha>`)
### Stage 5c — refactor + regression
- 全套既有 test pass: ✅
## Stage 6: Regression
- QA wave 重跑 (scope 含 downstream sweep ripple)
- 結果: ✅ / ❌
## Stage 7: Comparison QA
- 新 verifier 不告知原 QA 結果, re-audit
- 結論: 跟原 QA 一致 / 不一致
## Stage 8: Merge gate
- [ ] PR header 完整
- [ ] 宣告的「滿足」INV: ✅
- [ ] 宣告的「可能影響」INV regression: ✅
- [ ] 兩個 QA agent 結論一致
- [ ] OPEN list 清空
- [ ] unit test 綠
- [ ] 如影響 UI: manual smoke happy path
---
## Cycle close
- **Closed**: YYYY-MM-DD HH:MM
- **Outcome**: merged-on-dev / abandoned / split into Cn+1
- **Total commits**: <count>
- **New INVs added**: <list>
- **Bugs fixed**: <count>
- **Lessons** (going to brain): <bullet points>
檔案 3/4 — docs/invariants.md
專案的 invariant 契約 catalogue。初始空白,隨 cycle 累積。每修一個 bug 必須在這加對應條目——沒加不算修完。半年後 grep 某個 INV ID 應該找得到「誰加的、為什麼加、對應哪個 test」。
# Invariants — Project Contract Catalogue
> Every invariant here is a contract. Code must hold. Tests must verify.
> Format: `INV-<CATEGORY>-<NNN>: <statement>` + origin + severity + test ref.
## Categories (調整為你專案實際需要的)
- `INV-AUTH-*` — authentication / session / token rotation
- `INV-RBAC-*` — role-based access control / capability checks
- `INV-RLS-*` — row-level security (multi-tenant isolation)
- `INV-DATA-*` — data integrity / nullability / FK / atomicity
- `INV-IDEM-*` — idempotency (probe-then-INSERT, advisory locks)
- `INV-INPUT-*` — input validation / sanitization
- `INV-UI-*` — frontend behavior contracts
- `INV-RESOLVER-*` — resolver-level contracts (scope, error shape)
- `INV-SCHEMA-*` — schema design constraints (反 over-design 用)
- `INV-BATCH-*` — batch operation invariants
## Verification Layer Reference
每條 INV 標 verification layer:
- L0 spec / L1 INV / L2 schema / L3 resolver / L4 frontend / L5 E2E
(同一條 INV 可能 multi-layer。看本文 §5 對 6-layer doneness 的說明。)
---
## Invariants
### INV-AUTH-001 (example template — 換成你的)
- **Statement**: <one-line contract,可被測試直接驗證>
- **Origin**: Cycle C<n> (YYYY-MM-DD) — <short context, why this surfaced>
- **Severity**: P0 / P1 / P2
- **Test**: <path/to/test.go::TestFuncName> or <❌ TODO in backlog>
- **Enforcement layer**: L1 + L3
- **Related findings**: F-C<n>-NNN
---
## Backlog (test ❌ TODO)
當你寫了 INV 但 test 還沒寫完時, 標 ❌ 放這裡。半年後拿這個 backlog 跑「補測試 sprint」:
- ❌ INV-XXX-NNN (待補 integration test)
- ❌ INV-YYY-MMM (待補 E2E test)
---
(initial state: empty — populate as cycles surface bugs.
每 fix commit 必須在這加對應 INV, 沒加不算修完。)
檔案 4/4 — AGENTS.md
Role taxonomy + 資源預算。不寫具體職稱(架構師 / PM / UI-UX / 後端 / Flutter / DBA / QA)——那是死文件做法。寫的是「執行類型」(Writer / Verifier / Triage / Comparison / Newbie) + 機器資源上限,具體 staffing 在每個 cycle file 的 Header 裡。
# Agents — Role Taxonomy + Resource Budget
> Roles are **perspectives**, not headcount. Agent count is an OUTPUT
> of staffing per cycle, declared in each cycle file Header.
> This file holds only the **invariant** parts: budget ceiling + type taxonomy.
## Resource Budget (本機, 改成你的數字)
| Item | RAM | Notes |
|------|-----|-------|
| Total RAM | 32 GB | This machine |
| OS + Docker + browser reserve | ~7 GB | Baseline |
| **Available for agents** | **~22 GB** | Max budget |
## Model Memory Reference (Claude Code)
| Model | RAM | When to use |
|-------|-----|-------------|
| Opus | ~1.0 GB | architecture / cross-file reasoning / security / senior thinking |
| Sonnet | ~0.6 GB | implementation / API / tests / documentation |
| Haiku | ~0.4 GB | file scanning / config compare / simple SQL / read-only audit |
口訣:需要「想」→ Opus | 需要「做」→ Sonnet | 需要「找」→ Haiku
## Role Taxonomy (perspectives, not job titles)
| Type | Action | Parallelizable? | Typical model | Notes |
|------|--------|----------------|---------------|-------|
| **Writer** | mutate files (code / SQL / migration / spec) | NO (single-thread) | Sonnet / Opus | 同時只 1 個 |
| **Verifier** | read-only inspection / red-team / regression | YES | Haiku / Sonnet | scope 鎖死 1-3 INV |
| **Triage** | classify findings (bug / feature / usage / not_issue) | NO (sequential) | Sonnet (或人類) | PM authority |
| **Comparison** | independent re-verify (Stage 7) | YES (with #1 verifier) | Haiku | 不知道原 QA 結果 |
| **Newbie** | adversarial persona audit (broader coverage) | YES | Sonnet | each persona explicit prompt |
## Per-Cycle Staffing (declared in cycle file Header)
每個 cycle 在自己的 `docs/cycles/Cn-*.md` Header 宣告本輪派多少 agent。範例:
| Agent ID | Type | Model | RAM | Scope |
|----------|------|-------|-----|-------|
| RD-1 | Writer | Sonnet | 0.6 GB | 整個 cycle 寫入 |
| QA-A | Verifier | Haiku | 0.4 GB | INV-XXX-NNN red-team |
| QA-B | Verifier | Haiku | 0.4 GB | INV-YYY-MMM regression |
| QA-C | Comparison | Haiku | 0.4 GB | Stage 7 (盲 re-audit) |
| PM-Tri | Triage | Sonnet | 0.6 GB | Findings ≥3 才派 |
**Memory budget check**: 加總 ≤ available。Over budget → merge 兩個最低 scope Verifier。
## Iron Rules (執行契約, 違反退回)
1. **一個 cycle 同時只能 1 個 Writer agent 動手**。其他 agent 都不准動 code / spec / schema / migration。
2. **Verifier 永遠不准標 P0/P1**——只能 ✅ / ❌ / OPEN。
3. **Verifier scope 必須鎖死 1-3 個 INV**。不准「找任何 bug」。
4. **TDD red-green 必拆 5a / 5b / 5c 三 commit**。
5. **cycle file 必須留檔**, 跨 cycle 不刪。
6. **每月 retro 一次, amend workflow.md 或 AGENTS.md**——這份檔死掉就跟 staffing 死掉一樣慘。
4 個檔放好之後,接下來那段 bootstrap prompt 就有東西可指了——每個動作都對應到上面具體的檔案內容。
5 個 type 的事故來源 — 入門篇深挖
看到 AGENTS.md 列 Writer / Verifier / Triage / Comparison / Newbie 5 個 type,你可能會想:「為什麼不直接用傳統 8 職稱(架構師 / PM / UI-UX / 後端 / Flutter / DBA / QA)?」答案是這 5 個 type 不是想像出來的,是踩過真實角色事故反推出來的補丁——21 輪 ping pong、11 輪 self-audit 漏 P1、5 persona 抓 23 finding。每個 type 對應一條具體事故。
故事完整版在入門篇用第一人稱寫:「為什麼修不完?」— 從 21 輪迴圈到 5 type taxonomy 的多 agent 角色設計。沒看過入門篇的讀者建議先回頭讀,再看本篇 5 個 type 怎麼用會更有 context。
另一個跟 type 並列的設計選擇是 per-cycle dynamic staffing:不是「每 cycle 派固定 N 個 agent」,而是每個 cycle 在 docs/cycles/Cn-*.md Header 自己宣告派哪些 type、什麼 model、佔多少 RAM,加總要 ≤ machine available。改 1 行 typo 跟改 schema 不會用同樣編制。同樣在入門篇的故事裡詳細展開。
Bootstrap prompt(複製貼到新 session 的開場白)
你接手這個專案。第一輪 onboarding 強制讀以下檔案,讀完再開工:
1. docs/workflow.md — 8-stage cycle SOP,所有 PR 必經
2. docs/cycle-template.md — cycle file 結構,每個 PR 複製一份
3. docs/invariants.md — 所有 invariant 契約,改動前先看會影響哪幾條
4. AGENTS.md — 本機資源預算 + role taxonomy
從現在開始,所有改動走 cycle file 流程:
1. 開 PR 前 git checkout -b feat/<topic>
2. 從 cycle-template.md 複製成 docs/cycles/Cn-<topic>.md
(n = 流水號,grep 既有 docs/cycles/ 看下一個 n 是什麼)
3. 填 Header(owner / start time / cycle type / related INV)
4. 跑 Stage 0.5 pre-cycle hygiene 確認 baseline 乾淨
5. 進 Stage 1 RD 自測 → Stage 2 QA wave → ... → Stage 8 merge gate
6. 收尾時 cycle file commit 留檔,絕對不刪
紀律:
- QA agent 永遠不准標 P0 / P1(那是 PM 的 authority)
- 任何 fix 必須 5a 寫 failing test 紅燈 → 5b 寫 fix 綠燈 → 5c refactor
- 任何改動先 grep 找 downstream reader,沒列必漏
- cycle file 寫具體 evidence,不寫抽象 status
- 修了 bug 必須加 INV 到 docs/invariants.md,沒加不算修完
不確定的 stage 先問我,不要自己腦補。
這段直接 paste 進新 Claude Code session、Antigravity initial message、Codex 的第一輪 prompt、或 Cursor 的 chat input 都能用。共通點是這些工具都讀 markdown,所以方法論本身跨工具。
跨工具相容性——自動觸發機制
差別不在「方法論能不能跑」,在「自動觸發機制」。每個工具有自己的「啟動時必讀」slot:
| 工具 | 自動觸發 slot | 怎麼放 bootstrap |
|---|---|---|
| Claude Code | CLAUDE.md(專案根目錄)+ ~/.claude/skills/ |
CLAUDE.md 第一段宣告「## Domain Skill: cycle-workflow」+ skill 寫 cycle SOP 引導 |
| Codex / OpenAI Agent | AGENTS.md(OpenAI 協議) |
AGENTS.md 開頭加「啟動時讀 docs/workflow.md 必經 8-stage」段落 |
| Antigravity | 專案 root system prompt | 同上,在 system prompt 內 reference docs/workflow.md |
| Cursor | .cursorrules |
.cursorrules 寫「每次回應前讀 docs/workflow.md」+ reference cycle template |
| Aider | .aider.conf.yml / CONVENTIONS.md |
CONVENTIONS.md 寫 cycle SOP 要點,啟動時 –read 進去 |
| 純 ChatGPT / Claude Chat | 無自動 slot | 手動 paste 上面 bootstrap prompt 進每個新對話 |
關鍵 insight:方法論存 markdown,觸發機制存工具專屬 slot。換工具時方法論不用重寫,只要更新觸發機制怎麼指向同樣那 4 個檔案。
持續 update 機制——別讓 kit 變死文件
啟動只是第一步。長期維護有三條強制 update trigger,少了任何一條,kit 半年後就會 rot:
- 每
fix:commit 強制 updateinvariants.md:修了 bug 必須加對應 invariant,沒加不算修完。沒這條,同類 bug 半年後一定回來。 - 每 cycle 收尾 commit
docs/cycles/Cn-*.md:cycle file 留檔不刪,當作 audit trail + 給未來 cycle 參考。沒這條,cycle 跑完就忘,跨 cycle lesson 全部蒸發。 - 每月 retro amend
workflow.md:跑了一個月會發現某個 stage 太重 / 漏 / 順序不對。retro 看數據(漏掉的 bug、浪費的 stage、卡住的 finding),回去 amend SOP。沒這條,workflow.md 變死文件。
這三條 trigger 應該寫進 workflow.md 自身,讓「每個 agent 開工前必讀 workflow」這個動作自動帶上「該 update 什麼」的提醒。
第一個專案的 day-1 動作
git init+ 建docs/cycles/目錄- 把上面 4 個檔案複製進來(
workflow.md/cycle-template.md/invariants.md空白 /AGENTS.md) - 建
CLAUDE.md(or 對應工具的 root prompt 檔)宣告必讀那 4 個 - 第一個 PR 就照 cycle file 流程走——不要說「先簡單做,以後再上 SOP」,以後不會來
- 跑完第一個 cycle,commit cycle file + 第一條 invariant + 第一輪 workflow.md amend(會發現自己漏寫了什麼)
這套不需要先「累積經驗」才能啟動。第一個 cycle 跑完就有第一份 cycle file 範例給未來自己 / 未來 agent 看,雪球從第一天就開始滾。
§8 反模式——cycle file 怎麼寫會死掉
- 寫太抽象:只列 status(
QA: ✅),沒列 evidence(哪個 invariant、哪個 attack scenario、reproduce 步驟)。半年後讀不懂自己寫了什麼。 - 寫太瑣碎:每個 keystroke 記 timestamp,cycle file 變成 chat log。讀的人撈不到結論。
- 不留 cycle file:對話結束就忘,跨 session 必撞失憶。最常見也最致命。
- 不分 stage:一個 cycle 寫成一坨流水帳。新 agent 不知道現在跑到哪。
- 寫在 cloud doc / Notion 不是 git:沒 audit trail,branch 切換 cycle file 不會跟著切,跨工具不依賴的好處全部失去。
- 不分 Cycle Type 硬跑 8-stage:user-smoke-followup 跑 Stage 2 QA wave 等於把 user 抓的 bug 丟回給 QA agent 確認——錯位、浪費。
結語:接力棒不是裝飾,是 multi-agent 工程的真正關鍵
Multi-agent 工程兩條互補規則:
- 動手的 agent 只能一個(寫入單線程,從 Cognition / Stanford 等業界共識)
- 下一個 agent 必須能無痛接手(cycle file 接力棒,業界文章很少談)
多數人聽到「multi-agent」想到的是「多個 AI 一起工作」。實際上正確的設計是:同時間只有一個 AI 在動手,其他都是不動手的判斷者;動手的累了下一個來,接力棒(cycle file)不能丟。
業界文章很少談接力棒——他們談 orchestrator-subagent、談 generator-verifier、談 context isolation,但很少談「下一個 agent 從哪裡讀狀態」。可能因為 demo 場景太短,撞不到 compaction 也撞不到跨 session 失憶。長期專案跑下來,這個盲區會反覆把人燒一遍。
Cycle file 是踩坑長出來的工程紀律。file-as-state-machine pattern 可以推廣到所有需要「process state 跨人 / 跨時間延續」的場景——不分是不是 multi-agent。
延伸閱讀
- 本系列上一篇:「56 條 INV 全綠,user 點一次抓出 4 個 bug」— Multi-Agent 業界共識的五個自家補丁
- Multi-Agent 架構再探: 三省六部反模式和業界收斂共識(愛好 AI 工程,2026-05-19)
- ADR organization — file-as-state-machine 的 architecture-decision 變體
- RFCs and Design Docs — Pragmatic Engineer 講 RFC 的 multi-step review pattern
發佈留言