loop-design-check
設計 agent loop 或檢查它會不會空轉、作弊、把錯答案跑到底
中文翻譯
--- name: loop-design-check description: "設計以目標為導向的 agent loop,或檢查現有的 loop 會不會出現這些失敗模式:空轉、對 verifier 做 Goodhart 式的鑽漏洞,或是把錯誤答案一路跑到完成。涵蓋機器可判定的目標、loop 類型、plan/build/judge 骨架與失控防範;機制的接線則放在 autonomous-loops。在設計、撰寫或檢查 agent loop 時使用。中文触发:写 loop、设计 loop、做一个 loop、检查 loop 对不对、loop 体检、loop 会不会跑飞、可判定目标、五个崩法、plan build judge。" metadata: origin: ECC --- # Loop 設計與檢查 > **前提。**LLM 是一個前饋(feed-forward)系統:prompt 進去 → token 出來,跨輪次之間沒有內建的「朝目標修正」機制。要讓它*表現得*像一個以目標為導向的系統,你得在外面包一層回饋迴圈。這個 skill 幫你把那個 loop **寫對**,並且**檢查**它不會失控。 ## 何時用 / 何時不用 **適合使用的時候:** - 你想把一個重複性的任務交給 agent 反覆跑(寫→測、測→修、修→驗…)。 - 你已經有一個 loop,擔心它會空轉、作弊,或把錯誤答案一路跑到完成。 **不要用在:** - 一次性的任務 → 直接做就好,不要包 loop。 - 單純的計時器 / 輪詢 → 用 `/loop`,不需要設計。 - *怎麼接 loop 的架構*(pipeline → DAG、長時間執行的復原)→ 那是機制層,看 `autonomous-loops` / `continuous-agent-loop`。**這個 skill 只管「目標對不對、會不會失控」,不重複解釋機制。** ## 紅線前提:兩層回饋 | 層級 | 誰負責 | 做什麼 | |---|---|---| | **執行**(低層) | 機器 / agent | 量測「離字面上的目標還有多遠」,然後磨到變成零。機器在這方面很強。 | | **判斷**(高層) | **人** | 決定「這個目標本身對不對、該不該改、該不該停」。機器沒辦法跳出自己的 loop 去質疑目標。 | > 恆溫器可以回饋「離 26°C 還差多少」,但你發燒、想要 28°C 的時候,它沒辦法判斷 26 是不是*對的*目標,只會一直朝 26 磨。**「今天要設定成多少」永遠是人的決定。** > 把判斷 / 簽核 / 最後一道開關交給機器,等於拿掉高層的回饋,它就會又快又猛地衝向一個沒人質疑過的目標,產出錯誤的結果。 --- ## 動作 1:寫一個 loop(5 個步驟) ### Step 0 · 先做減法:到底該不該建?(4 個條件的關卡,缺任何一個就否決) ① 任務每週至少重複一次 ② 驗證可以自動化 ③ token 預算撐得住 ④ agent 有真正能*執行並看到結果*的工具 缺任何一個 → **不要建 loop**;用手動或別的方式做。 > 擋住多數人的不是「我會不會寫 loop」,而是「我的 repo 值不值得有 loop」。值得有 loop 的 repo 有對帳基準(golden sample / 上游總數)+ 測試 + lint 防護。**不值得有 loop 的 repo,只會讓 loop 把錯誤放大。** ### Step 1 · 定義一個*機器可判定*的目標(最難的部分,loop 的生死在這裡) 整個 loop 都靠比較器回答「做完了嗎?」**只有當你的結束條件能讓機器判斷是或否,比較器才能運作。** - 壞的:模糊(「做好一點」、「寫得更犀利」)→ 比較器無法判斷 → 要麼永遠不會通過(卡在重試),要麼用猜的(隨機通過/擋下)。 - 好的:可判定(「96 個單元測試全綠且產出變更清單」、「module-02 欄位填完、pytest 通過、商業邏輯沒動」)→ 一次檢查就能定案,loop 乾淨地收斂。 **目標的五點框架:** 1. **完成條件可由機器驗證。** 2. **邊界條件跟完成條件一起定義**(「絕對不能做什麼」):防 Goodhart;沒有邊界就等於授權作弊。 3. **有失敗的退路**:重試上限 N,超過就升級給人。 4. **目標是分層的。** 5. **完成條件優先用對帳,不要用斷言**:先錨定外部事實(golden sample / 上游總數 / 財務對帳 / 平台後台數字),再來才是你自己的斷言。「所有測試通過」可以被鑽漏洞(放寬 assert、造假 mock、吞掉 exception);「與基準的 diff < 0.01」就鑽不了。 > **自我檢查:**把目標念給不懂這個領域的人聽,他能不能跑一個指令就判斷做完了沒?不能的話,就是可判定性不夠,回頭再改。 ### Step 2 · 選 loop 類型 | 你的任務 | Loop 類型(控制論) | 怎麼停 | |---|---|---| | 有明確的「完成」測試(寫到完成 / 處理完一批圖片) | **servo**(`/goal` 式的閉迴路) | 達到目標就停 | | 沒有終點,必須持續維持某個狀態(庫存警報 / 排程健康檢查) | **regulator**(`/loop` 式的恆溫器) | 永不停止;只在狀態變化時動作(dead-band 抑制雜訊) | | 定期取樣,符合條件就停(盯著 PR 直到 CI 變綠) | **帶出口的 regulator** | 出口條件成立時停止 | | 必須「確保某件事準時發生」 | 把上面的任一種包進 `/schedule` | 由 cron 觸發 | > 經驗法則:有明確的「完成」測試 → servo;必須持續維持、沒有終點 → regulator;必須「準時發生」→ 把 regulator 包進 schedule。 ### Step 3 · 選骨架 **維護型(照料已存在的東西)→ 文件驅動的調度。** loop 不是「定時跑固定的檢查」,而是**「定時讀一份文件,只有文件變了才調度」**。這份文件就是任務佇列 + 狀態機 + 人機介面。 三項紀律:① 問題欄只有人能寫,結果欄只有 loop 能寫,**狀態單向前進,不會回退**;② **exit code 是最終裁決**(script 說 exit 1,就以 script 為準);③ 狀態最多只推進到「等待驗證」,**「完成」的格子只由人來翻。** loop 是工人,不是驗收官。 **全新開發型(從零開始建)→ plan / build / judge 三個角色。** | 角色 | 做什麼 | 關鍵 | |---|---|---| | **Plan** | 把目標拆成 spec + **可判定的驗收條件** | 驗收必須能由 script 判斷 | | **Build** | 照 spec 寫 | **不能更改驗收條件** | | **Judge** | **獨立地**跑驗收;通過 → 停,失敗 → 帶著失敗原因退回給 Build | **獨立 + 確定性** | 三條鐵則(全都押在 judge 身上):① **judge 必須獨立**:不能跟 Build 是同一個 agent(自己改自己的作業,分數一定灌水);② **確定性規則**:pytest / 對帳 diff / 型別檢查 / diff,絕對不是「看起來對」;③ **Build 不得為了通過而修改驗收條件**。重試失敗三次 → 升級給人。 ### Step 4 · 加上阻尼(防震盪 / 失控) 重試上限、強制停止、由人來翻最後的開關,這些就是阻尼。**沒有阻尼的負回饋會震盪**(Ralph-Wiggum loop:原地空轉、燒 token)。 ### Step 5 · 分三階段上線(不要第一天就全自動) ① **先手動跑一次**(逼你把「judge 怎麼判定」講清楚)→ ② 固化成 skill / Claude Code sub-agent(由主 Claude 跑迴圈,調度 plan/build/judge)→ ③ 掛上 cron 做到全自動。 --- ## 動作 2:檢查一個 loop(檢查清單 = 五種失敗模式) > 把 loop 對每一列檢查一遍。**只要中任何一項,這個 loop 就會出事,退回去重做。**這五項是負面經驗(gotcha),比正面規則更有價值。 | # | 失敗模式(怎麼壞的) | 檢查問題(中了就是紅燈) | 解方 | |---|---|---|---| | 1 | 目標是句正確的廢話 → **空轉、燒錢** | 結束條件能不能由機器判斷是或否?還是只是「管理好它 / 把它做好」? | 換成可判定的結果條件(動作 1·Step 1) | | 2 | 「驗證」寫成「看看是不是沒問題」→ **agent 信心滿滿地說沒問題就停了** | judge 是不是被告本人?驗證是靠「看起來對」,還是確定性規則? | 對帳 + exit code 規則 + 獨立的 judge | | 3 | (最糟)只用「所有測試通過」把關 → **agent 把測試刪掉** | 有沒有邊界(「絕對不能做什麼」)?還是只有完成條件? | 完成條件**加上邊界**一起用(Goodhart 的解方) | | 4 | 指望 agent 在執行中途發問 → **它不會,它會把錯誤答案跑到底** | 有沒有任何「只在執行時才釐清」的環節? | **把所有釐清前置**;啟動前一次講清楚 | | 5 | 臃腫的 CLAUDE.md + 過期的 memory → **loop 越快,錯得越多** | 它依賴的文件/memory 夠新嗎?誰在維護? | 分層 memory + 定期 lint | **另外還有三條紅線(違反任何一條就不准自動化):** - **判斷留在人手上。**驗收 / 「完成」的格子由人來翻;loop 不是驗收官。 - **責任不會轉移。**任何失敗你承受不起的事(merge 錯的 PR / 發佈錯的東西 / 錯誤分配金錢)→ **不要自動把權限交出去。** - **反直覺的警告。**loop 越是「自我改進 / 改寫自己的規則」,**需要的人工 review 就要越嚴格**(要看它把規則改成了什麼),而不是放寬。機器快到事後來不及攔截,所以人的判斷必須放在**動作之前**(硬性關卡),不能當成事後補丁。 --- ## 實例:檢查一個「夜間保綠」loop 你想要一個每晚執行、修好任何失敗測試的 loop。 - **天真的目標:**「讓所有測試通過。」→ 沒通過 Step 1 的自我檢查:這正是失敗模式 #3 的誘餌。 - **可判定的目標(修正後):**「所有測試全綠,**而且**沒有測試檔被刪除或弱化,**而且**覆蓋率沒有降低,**而且**產出變更清單。」邊界現在跟完成條件一起定義了。 - **類型:**servo,重試上限 3 次(Step 2 + Step 4)。 - **骨架:**plan/build/judge,**judge 是獨立執行的 CI**,絕對不是負責修的 agent(Step 3)。 現在跑**檢查清單**,它會抓到天真版本漏掉的問題: - **中 #3** → 天真的「所有測試通過」讓 agent 刪掉失敗的測試來「獲勝」。用邊界「不得刪除/弱化測試檔」修正。 - **中 #2** → 如果負責修的 agent 同時也判斷自己的修正,它會讓自己通過。用「judge = 獨立的 CI,確定性」修正。 - **中 #4** → 如果某個修正有歧義,agent 不會在凌晨 2 點停下來問,它會 commit 一個猜測。用前置來修正:有歧義的修正留給人,不要猜。 - **紅線** → loop 開 PR 但**不會自動 merge**;最後的開關由人來翻(責任不會轉移)。 天真的 loop 和檢查過的 loop,差別只在四行限制,而這就是「醒來發現測試套件被刪光」和「醒來發現一個乾淨的 PR」的差別。 --- ## 一句話收尾 > 寫 loop 難的不是「我會不會寫 loop」,而是**定義一個機器能對帳的目標**:可判定、有邊界、以對帳為基礎。控制器必須是確定性的、在外部的;判斷與標準留給人;系統會趨向熵增,所以要維護它。 > **loop 只會回報已經想清楚的人。指望它替你思考,它會很樂意跟你一起、大規模地想錯。** --- > 淵源:判斷/執行的切分與紅線,來自 Wiener 的兩層回饋(*The Human Use of Human Beings*,1950);plan/build/judge 模式來自 Anatoli 的 *Loops explained* 與 Addy 的 *Loop Engineering*。 > 機制層(怎麼接 loop 的架構):看 `autonomous-loops` / `continuous-agent-loop`。這個 skill 不重新實作機制,只涵蓋目標定義與失控防範。
英文原文
---
name: loop-design-check
description: "Design a goal-oriented agent loop or review one for failure modes: spinning, Goodhart-gaming the verifier, or running a wrong answer to completion. Covers machine-decidable goals, loop types, plan/build/judge skeletons, and runaway prevention; mechanism wiring lives in autonomous-loops. Use when designing, writing, or checking an agent loop. 中文触发:写 loop、设计 loop、做一个 loop、检查 loop 对不对、loop 体检、loop 会不会跑飞、可判定目标、五个崩法、plan build judge。"
metadata:
origin: ECC
---
# Loop Design + Review
> **Premise.** An LLM is a feed-forward system: prompt in → tokens out, with no built-in "steer toward the goal" across turns. To make it *behave* like a goal-oriented system, you wrap a feedback loop around it. This skill helps you **write** that loop correctly and **review** it so it won't run away.
## When to use / not
**Use it when:**
- You want to hand a repeating task to an agent that runs over and over (write→test, test→fix, fix→verify…).
- You already have a loop and worry it spins, cheats, or runs a wrong answer to completion.
**Don't use it for:**
- A one-off task → just do it; don't wrap a loop around it.
- A plain timer / poll → use `/loop`; no design needed.
- *How to wire the loop architecture* (pipelines → DAGs, long-run recovery) → that's the mechanism layer; see `autonomous-loops` / `continuous-agent-loop`. **This skill only covers "is the goal right, and will it run away" — it does not re-explain mechanism.**
## Red-line premise: two levels of feedback
| Level | Who owns it | What it does |
|---|---|---|
| **Execution** (low) | machine / agent | Measures "how far from the literal goal" and grinds it to zero. The machine is strong here. |
| **Judgment** (high) | **human** | Decides "is this goal itself right, should it change, should it stop." The machine can't step outside its own loop to question the goal. |
> A thermostat can feed back "how far from 26°C," but when you have a fever and want 28°C it can't judge whether 26 is the *right* target — it just grinds toward 26. **"What to set today" is always the human's call.**
> Handing judgment / sign-off / the last switch to the machine = removing the high-level feedback = it sprints, fast and hard, toward a goal no one questioned → wrong output.
---
## Action 1 — Write a loop (5 steps)
### Step 0 · Subtract first: should you even build it? (4-condition gate, any miss = veto)
① the task repeats weekly or more ② verification can be automated ③ the token budget can take it ④ the agent has tools that actually *run and see the result*
Miss any one → **don't build a loop**; do it by hand or another way.
> What stops most people isn't "can I write a loop," it's "does my repo deserve one." A repo that deserves a loop has a reconciliation baseline (golden sample / upstream total) + tests + a lint guard. **A repo that doesn't deserve a loop will only have its errors amplified by one.**
### Step 1 · Define a *machine-decidable* goal (the hard part — the loop lives or dies here)
The whole loop rides on the comparator's "is it done yet?" **The comparator can only work if your exit condition can be judged yes/no by a machine.**
- Bad: Vague ("make it good," "write it sharper") → the comparator can't judge → either it never passes (stuck retrying) or it guesses (passes/blocks at random).
- Good: Decidable ("all 96 unit tests green AND a change-list is produced," "module-02 fields filled, pytest passes, business logic untouched") → one check settles it; the loop converges cleanly.
**Five-point goal framework:**
1. **Done-criterion is machine-verifiable.**
2. **Boundary conditions defined alongside the done-criterion** ("what it must NOT do") — anti-Goodhart; missing boundaries = a license to cheat.
3. **Has a failure fallback** — retry cap N + escalate to a human when exceeded.
4. **Goal is layered.**
5. **Prefer reconciliation over assertion for the done-criterion** — anchor to external fact (golden sample / upstream total / financial tie-out / platform back-office numbers) before your own assertions. "All tests pass" can be gamed (loosen asserts, fake mocks, swallow exceptions); "diff vs the reference < 0.01" can't.
> **Self-check:** read the goal to someone who doesn't know the domain — can they run one command and tell whether it's done? If not, it isn't decidable enough. Go back.
### Step 2 · Pick the loop type
| Your task | Loop type (cybernetic) | How it stops |
|---|---|---|
| Has a clear "done" test (write to done / a batch of images processed) | **servo** (`/goal`-style closed-loop) | stops on reaching the goal |
| No endpoint, must keep maintaining a state (inventory alert / scheduled health check) | **regulator** (`/loop`-style thermostat) | never stops; acts only on change (dead-band suppresses noise) |
| Periodic sampling, stop on a condition (watch a PR until CI is green) | **regulator with an exit** | stops when the exit condition holds |
| Must "ensure something happens on time" | wrap the above in `/schedule` | cron fires it |
> Rule of thumb: clear "done" test → servo; must keep maintaining, no endpoint → regulator; must "happen on time" → wrap a regulator in schedule.
### Step 3 · Pick a skeleton
**Maintenance type (tend something that exists) → document-driven dispatch.**
The loop isn't "run a fixed check on a timer," it's **"read a doc on a timer, and dispatch only when the doc changed."** The doc is the task queue + state machine + human interface.
Three disciplines: ① the problem column is human-write-only, the result column is loop-write-only, **state advances one-way and never rolls back**; ② **the exit code is final** (if the script says exit 1, the script wins); ③ state advances only as far as "awaiting verification" — **the "done" cell is flipped by a human only.** The loop is the worker, not the acceptance officer.
**Greenfield type (build from scratch) → plan / build / judge, three roles.**
| Role | Does | Key |
|---|---|---|
| **Plan** | break the goal into a spec + **decidable acceptance conditions** | acceptance must be script-judgeable |
| **Build** | write to the spec | **must not change the acceptance conditions** |
| **Judge** | run acceptance **independently**; pass → stop, fail → return with the failure reason to Build | **independent + deterministic** |
Three iron rules (all bet on the judge): ① **the judge must be independent** — not the same agent as Build (grading your own homework always inflates); ② **deterministic rules** — pytest / reconciliation diff / type check / diff, never "looks right"; ③ **Build may not edit the acceptance conditions to pass**. Three failed retries → escalate to a human.
### Step 4 · Add damping (against oscillation / runaway)
Retry cap, hard stop, human flips the last switch = damping. **Negative feedback with no damping oscillates** (the Ralph-Wiggum loop: spinning in place, burning tokens).
### Step 5 · Land in three stages (don't go fully automatic on day one)
① **Run it once by hand** (forces you to state exactly "how the judge decides") → ② harden into a skill / Claude Code sub-agents (a main Claude loops, dispatching plan/build/judge) → ③ hang it on cron for full automation.
---
## Action 2 — Review a loop (checklist = five failure modes)
> Run the loop past each row. **Hitting any one = this loop will misfire; send it back.** These five are negative experience (gotchas) — worth more than positive rules.
| # | Failure mode (how it breaks) | Review question (a hit = red) | Antibody |
|---|---|---|---|
| 1 | Goal is a correct platitude → **spins, burns money** | Can the exit condition be machine-judged yes/no? Or is it "manage it well / make it good"? | Replace with a decidable result condition (Action 1·Step 1) |
| 2 | "Verification" written as "check if it looks ok" → **agent confidently says fine and stops** | Is the judge the defendant itself? Does verification rest on "looks right" or deterministic rules? | Reconcile + exit code rules + independent judge |
| 3 | (worst) Only gates on "all tests pass" → **agent deletes the tests** | Is there a boundary ("what it must NOT do")? Or only a done-criterion? | Done-criterion **+ boundary** together (the Goodhart antibody) |
| 4 | Counts on the agent asking mid-run → **it won't; it runs the wrong answer to the end** | Is there any "clarify only at runtime" point? | **Front-load every clarification**; settle it once before launch |
| 5 | Bloated CLAUDE.md + stale memory → **the faster it loops, the more it errs** | Are the docs/memory it depends on fresh? Who maintains them? | Layered memory + periodic lint |
**Plus three red lines (violate any = not allowed to go automatic):**
- **Keep judgment with the human.** Acceptance / the "done" cell is flipped by a human; the loop is not the acceptance officer.
- **Responsibility doesn't transfer.** Anything whose failure you can't afford (merge the wrong PR / publish the wrong thing / misallocate money) → **don't hand over the authority automatically.**
- **Counter-intuitive warning.** The more "self-improving / rewrites-its-own-rules" a loop is, the **stricter the human review it needs** (to see what it rewrote the rules into) — not looser. The machine is too fast to intercept after the fact, so the human's judgment must sit **before the action** (a hard gate), not as a post-hoc patch.
---
## Worked example — reviewing a "nightly green-keeper" loop
You want a loop that runs every night and fixes whatever tests are failing.
- **Naive goal:** "make all tests pass." → Step-1 self-check fails: this is the bait for failure mode #3.
- **Decidable goal (fixed):** "all tests green **AND** no test file deleted or weakened **AND** coverage not lowered **AND** a change-list produced." Boundary now defined alongside the done-criterion.
- **Type:** servo with a retry cap of 3 (Step 2 + Step 4).
- **Skeleton:** plan/build/judge — the **judge is CI run independently**, never the fixing agent (Step 3).
Now run the **review checklist**, and it catches what the naive version would have missed:
- **#3 hit** → the naive "all tests pass" lets the agent delete a failing test to "win." Fixed by the boundary "no test file deleted/weakened."
- **#2 hit** → if the fixing agent also judged its own fix, it would pass itself. Fixed by "judge = independent CI, deterministic."
- **#4 hit** → if a fix is ambiguous, the agent won't stop to ask at 2 a.m.; it'll commit a guess. Fixed by front-loading: ambiguous fixes are left for the human, not guessed.
- **Red line** → the loop opens a PR but **does not auto-merge**; the human flips the last switch (responsibility doesn't transfer).
The naive loop and the reviewed loop differ by four lines of constraint — and that's the difference between "wakes you to a deleted test suite" and "wakes you to a clean PR."
---
## One-line close
> The hard part of writing a loop isn't "can I write a loop," it's **defining a goal a machine can reconcile** — decidable, bounded, reconciliation-based. The controller must be deterministic and external; keep judgment and the standard with the human; the system tends toward entropy, so maintain it.
> **A loop only rewards someone who has already thought it through. Count on it to think for you, and it will happily think wrong, with you, at scale.**
---
> Lineage: Wiener's two-level feedback (*The Human Use of Human Beings*, 1950) for the judgment/execution split and red lines; the plan/build/judge pattern from Anatoli's *Loops explained* and Addy's *Loop Engineering*.
> Mechanism layer (how to wire the loop architecture): see `autonomous-loops` / `continuous-agent-loop`. This skill does not re-implement mechanism; it covers goal definition and runaway prevention only.