# LOOP ⭢ GRAPH ⭢ HARNESS: build the whole pipeline in one sitting
**作者**: Archive
**日期**: 2026-07-24T11:49:07.000Z
**来源**: [https://x.com/ArchiveExplorer/status/2080621294979023358](https://x.com/ArchiveExplorer/status/2080621294979023358)
---

Your agent re-reads the whole spreadsheet every turn. The whole codebase. The whole doc.
It finds something, forgets it, finds it again next turn - and you pay for those tokens twice, three times over.
The reflex is a bigger window, or a smarter model. Neither helps.
The problem isn't capacity. It's that everything the agent touches stays in the one window it thinks in.
The mental model: three layers, not three skills
A single model call answers once and stops. An agent has to do three harder things, and each one is a layer:
1. Do a unit of work in a controlled cycle - try, check, retry until it's actually right. That's the loop.
2. Split work too big for one cycle across many cycles - and keep each cycle's mess out of the others. That's the graph.
3. Run all of that on a substrate that hands each cycle its tools, its own clean context, and a safety boundary. That's the harness.
They don't compete. They nest:
The fix is a three-layer pipeline, and by the end of this you'll have it running locally. We build it bottom-up:
```
HARNESS -- the runtime everything executes inside (Layer 3)
|__ GRAPH -- several loops, fanned out and checked (Layer 2)
|__ LOOP -- one worker: gather -> act -> verify (Layer 1)
```
Clone the finished version now so the code below is real, not pseudocode. No install, no key, no network:
```
git clone https://github.com/Archive228/loop-graph-harness
cd loop-graph-harness && ./run.sh
```
Every quote below is a verbatim line from a real talk, with its exact timecode - the one thing in this whole niche you can check against the tape. Most of these threads can't survive that check: 9 of 16 "courses" they quote don't exist as video. Ours do.
## Layer 1 - THE LOOP
A loop is not "a cycle." It's a unit of work with three named parts, and the third is the one that makes it an agent instead of a chatbot:
- Gather context - decide what goes into the model's window for this step. Too little and it answers blind; too much and it's slow, expensive, and distracted.
- Take action - produce a candidate: code, an edit, a tool call, an answer.
- Verify the work - a check decides accept or try again. This is the step everyone draws and nobody builds.

> "here is the three parts to an agent loop: first gather context, second taking action, and the third is verifying the work."
Gather, act, verify, repeat until verified. The whole discipline is one rule: the verifier is written before the action, and the loop cannot pass it. And the verifier should be a plain rule, not a model grading a model:

> "the best form of verification is rule-based... if it doesn't lint or compile - as many rules as you can, insert them."
Here is the loop, whole. It's twenty lines; the discipline is that the verifier exists first (src/loop.py):
```
def run_loop(material, act, verify, max_attempts=5):
failures = []
for attempt in range(1, max_attempts + 1):
candidate = act(material, failures) # ACT - sees prior failures as context
report = verify(candidate) # VERIFY - rule-based, written first
if report.passed:
return LoopResult(True, candidate, attempt)
failures = report.failures # the failure text IS the next context
return LoopResult(False) # budget spent -> ship nothing
```
Why this isn't a toy: the demo fails on purpose. The worker parses durations (1h52m, 30m, 0s...). Attempt 1 uses a parser that is correct on every input a person would think to try - and genuinely crashes on "0s":
```
def _parse_v1(text):
h = re.search(r"(\d+)h", text); m = re.search(r"(\d+)m", text); s = re.search(r"(\d+)s", text)
hours = int(h.group(1)) if h else 0
mins = int(m.group(1)) if m else 0
secs = int(s.group(1)) if s else 0
if hours or mins or secs: # for "0s" this is 0 or 0 or 0 -> False
return hours*3600 + mins*60 + secs
return int(text) # ...so int("0s") raises. Jagged.
```
That's the "jagged edge" Karpathy warns about - models peak on the obvious inputs and are "rougher on the edges" one input over (clip K1 · Karpathy 10:35). You don't catch it in review. The rule-based verifier does, and the loop retries with a boring, total parser. When you run the repo you see it happen:
```
PASS sheet-A: builds total=18420s attempts=1
PASS sheet-B: tests total=4830s attempts=2 <- attempt 1 failed on '0s', loop retried
PASS sheet-C: deploys total=12600s attempts=1
```
That is loop engineering: one unit a program has to approve before it ships.
## Layer 2 - THE GRAPH
Now scale the loop. Several workers, each on one slice, running at once, handing back small results:

> "multiple read sub agents going on at the same time... can this agent read and summarize sheet one? Sheet two? Sheet three? Then they return their results, and the agent maybe spins off more sub agents again."

> "spin up three sub agents to do this task. And it will do that."
Read clip again - he narrates fan-out, fan-in, fan-out-again and never says the word "graph," because from inside the system it isn't a topology you architect, it's a knob you turn. In code, the graph is only the wiring; each node is just a loop (src/graph.py):
```
def fan_out(harness, worker, items):
# one loop-worker per (task, slice) - each runs in its own clean context
return [harness.spawn(worker, task, material) for task, material in items]
```
The design rule for a graph node: decide what comes back before you spawn it. The parent's context grows by exactly the return value, so you design the return first. If you can't say in one sentence what shape comes back - a number, a list, a verdict - you haven't drawn a boundary, you've doubled your bill.
A returned answer you didn't check is just faster pollution, so the graph ends with a checker - and it must run clean, with no loyalty to the work that produced it:

> "you might even want an adversarial one... really go to town on it, with no sympathetic relationship to the work already done."

> "as the models get better at reasoning, you can have these sub agents to check the work of the main agent."
```
def adversarial_verify(harness, artifact, rules):
def checker(ctx, tools, task, material): # ctx is FRESH; sees the artifact only
broken = rules(artifact) # not how it was made - nothing to defend
return "REJECT: " + "; ".join(broken) if broken else "ACCEPT"
verdict = harness.spawn(checker, "adversarially verify", repr(artifact))
return str(verdict).startswith("ACCEPT")
```
The tests prove this gate has teeth - hand it a bad merge and it rejects. A graph without this last node is just an unverified system with a nicer diagram.
## Layer 3 - THE HARNESS
The two layers above kept calling harness.spawn(...). This is what that is: the runtime everything executes inside. The engineer lists what's in it:

> "in the harness you've got tools"

> "tools you run in a loop, then you have the prompts, and finally the file system. The file system is a way of context engineering."

> "research, compacting, hooks, memory - they're all these other things around the harness as well."
"tools you run in a loop." The loop is a component of the harness - which is why this is one stack, not three rival skills. The harness does two jobs for you.
Job 1 - make spawning cheap. You think about what to spawn, not how:

> "we take care of all of this for you in the harness so you can think about: what sub agents do I need to spin off?"

> "when you're running parallel sub agents... bash becomes very complex - there are lots of race conditions. There's a lot of work we've solved there."
And it prefers one general tool over a drawer of bespoke ones:

> "if you were designing an agent harness, you'd have a search tool and a lint tool and an execute tool. Instead, now Claude just uses grep."
Job 2 - keep every worker's context clean. This is the load-bearing method, and the one rule that makes isolation real (src/harness.py):
```
def spawn(self, worker, task, material):
child = Context() # <-- NEW, empty. NOT self.parent.
child.add(task); child.add(material) # heavy material enters the CHILD only
result = worker(child, self.tools, task, material)
self.parent.add(str(result)) # parent grows by the RESULT only
return result
```

> "the main thing is to avoid context pollution, so you wouldn't want to fork the context. You'd start a new context session."
Fork the parent's window into the child and you isolated nothing - you copied the mess. The child starts empty, reads its slice in its own window, and hands back one line. And when a swarm is running bash, the last layer of the harness is the one that contains it:

> "the last layer is sandboxing. Let's say someone has maliciously taken over your agent - what can it actually do?"
## Run it, and watch the bill stay flat
That's the pipeline. Bottom-up: a loop that a program must approve, a graph that fans loops out and checks them clean, a harness that makes both cheap and keeps their contexts isolated. ./run.sh prints the proof:
```
HARNESS event log (parent context grows by RESULTS, not by sheets):
spawn #1: child_ctx=58B parent +71B (sum sheet: sheet-A)
spawn #2: child_ctx=57B parent +69B (sum sheet: sheet-B)
spawn #3: child_ctx=53B parent +72B (sum sheet: sheet-C)
spawn #4: child_ctx=81B parent +6B (adversarially verify)
parent (main-agent) context size: 218 bytes - it never held a full sheet.
```
Three full sheets processed. The main agent's context - the thing you pay for every turn - ended at 218 bytes. No bigger window, no better model. Just boundaries with return types. That's the whole point the engineer keeps circling:

> "you should never read the entire spreadsheet into context, because it would take too much."

> "I'm on my fifth compact. I'm like - what? I've almost never done a compact before."
He almost never compacts because he almost never lets the window fill. That's the skill, and now it's running on your machine.
## Where to go next
The demo generator is scripted so it runs offline and deterministically. Swap src/workers.py's act for a real model call and nothing else changes - loop, graph, and harness don't know or care what produced the candidate. That's the test that the layering is honest.
Three questions - where's the boundary, what's the return type, how do you verify it. None of them is which of the three words goes in your bio.
The repo: github.com/Archive228/loop-graph-harness - ./run.sh from a clean clone, 9 tests. Full timecode-to-file map in its LECTURE.md.
## 相关链接
- [Archive](https://x.com/ArchiveExplorer)
- [@ArchiveExplorer](https://x.com/ArchiveExplorer)
- [3.6K](https://x.com/ArchiveExplorer/status/2080621294979023358/analytics)
- [github.com/Archive228/loop-graph-harness](https://github.com/Archive228/loop-graph-harness)
- [Upgrade to Premium](https://x.com/i/premium_sign_up)
- [7:49 PM · Jul 24, 2026](https://x.com/ArchiveExplorer/status/2080621294979023358)
- [3,608 Views](https://x.com/ArchiveExplorer/status/2080621294979023358/analytics)
- [View quotes](https://x.com/ArchiveExplorer/status/2080621294979023358/quotes)
---
*导出时间: 2026/7/25 11:33:57*
---
## 中文翻译
# LOOP ⭢ GRAPH ⭢ HARNESS: 一口气构建整个流水线
**作者**: Archive
**日期**: 2026-07-24T11:49:07.000Z
**来源**: [https://x.com/ArchiveExplorer/status/2080621294979023358](https://x.com/ArchiveExplorer/status/2080621294979023358)
---

你的 Agent 每一轮都会重读整个电子表格。整个代码库。整份文档。
它发现了某些东西,然后忘了,下一轮又发现了——而你为这些 Token 付了两次、三次的钱。
本能反应是开更大的窗口,或者用更聪明的模型。都没用。
问题不在于容量。而在于 Agent 触碰的所有东西都停留在它思考的那一个窗口里。
思维模型:三层,而非三种技能
单次模型调用回答一次就停了。一个 Agent 必须做三件更难的事,每一件都是一层:
1. 在受控的循环中做一个工作单元——尝试、检查、重试,直到真正做对。这就是 Loop(循环)。
2. 把一个周期消化不了的大工作拆分到多个周期中——并且让每个周期的混乱互不干扰。这就是 Graph(图)。
3. 把所有这一切运行在一个基板上,由它给每个周期分发工具、独立的干净上下文和安全边界。这就是 Harness(挽具/运行环境)。
它们互不竞争。它们互相嵌套:
解决方案是一个三层流水线,读到最后你会在本地把它跑起来。我们自底向上构建:
```
HARNESS -- 所有代码在其中执行的运行时 (Layer 3)
|__ GRAPH -- 多个循环,展开并检查 (Layer 2)
|__ LOOP -- 一个工人:gather -> act -> verify (Layer 1)
```
现在克隆完成版,这样下面的代码就是真的,不是伪代码。无需安装、无需密钥、无需网络:
```
git clone https://github.com/Archive228/loop-graph-harness
cd loop-graph-harness && ./run.sh
```
下面每段引用都来自一场真实演讲的原话,并附有精确的时间码——这是整个细分领域里唯一能跟录像核对的东西。大多数帖子经不起这种核对:它们引用的 16 个“课程”里有 9 个并不作为视频存在。我们的存在。
## Layer 1 - THE LOOP(循环)
循环不是“一个周期”。它是一个带有三个具名部分的工作单元,而正是第三部分让它成为 Agent 而非聊天机器人:
- Gather context(收集上下文)——决定这一步把什么放进模型的窗口。太少,它就像盲人摸象般回答;太多,它就慢、贵且分心。
- Take action(采取行动)——产出一个候选结果:代码、修改、工具调用、答案。
- Verify the work(验证工作)——一次检查决定是通过还是重试。这是每个人都画出来却没人构建的一步。

> "这里是一个 Agent 循环的三个部分:首先是收集上下文,其次是采取行动,第三是验证工作。"
收集,行动,验证,重复直到通过。整个原则只有一条规则:验证器必须在行动之前写好,而且循环无法绕过它。并且验证器应该是一条简单的规则,而不是一个模型给另一个模型打分:

> "最好的验证形式是基于规则的……如果无法通过 lint 或编译——尽可能多地插入规则。"
这就是完整的循环。只有二十行;其原则在于验证器优先存在:
```
def run_loop(material, act, verify, max_attempts=5):
failures = []
for attempt in range(1, max_attempts + 1):
candidate = act(material, failures) # ACT - 将先前的失败视为上下文
report = verify(candidate) # VERIFY - 基于规则,优先编写
if report.passed:
return LoopResult(True, candidate, attempt)
failures = report.failures # 失败文本就是下一个上下文
return LoopResult(False) # 预算耗尽 -> 什么都不交付
```
为什么这不是玩具:演示故意让它失败。Worker 解析时长(1h52m, 30m, 0s...)。第一次尝试使用的解析器对任何正常人想到的输入都是正确的——但在 "0s" 上真的会崩溃:
```
def _parse_v1(text):
h = re.search(r"(\d+)h", text); m = re.search(r"(\d+)m", text); s = re.search(r"(\d+)s", text)
hours = int(h.group(1)) if h else 0
mins = int(m.group(1)) if m else 0
secs = int(s.group(1)) if s else 0
if hours or mins or secs: # 对于 "0s",这是 0 or 0 or 0 -> False
return hours*3600 + mins*60 + secs
return int(text) # ...所以 int("0s") 报错。参差不齐。
```
这就是 Karpathy 警告过的“参差不齐的边缘”——模型在明显的输入上达到顶峰,而在“边缘”的输入上表现“更粗糙”(clip K1 · Karpathy 10:35)。你在审查中抓不住它。基于规则的验证器能抓住,然后循环用一个无聊的、全覆盖的解析器重试。当你运行仓库时你会看到它发生:
```
PASS sheet-A: builds total=18420s attempts=1
PASS sheet-B: tests total=4830s attempts=2 <- attempt 1 failed on '0s', loop retried
PASS sheet-C: deploys total=12600s attempts=1
```
这就是循环工程:一个程序必须批准才能交付的单元。
## Layer 2 - THE GRAPH(图)
现在扩展循环。多个 Worker,每个处理一个切片,同时运行,交回小结果:

> "多个读取子代理同时进行……这个代理能读取并总结表格一吗?表格二?表格三?然后它们返回结果,代理可能再次分出更多子代理。"

> "分出三个子代理来做这个任务。它会照做。"
再读一遍剪辑——他叙述了展开、归并、再展开,却从未说出“图”这个词,因为从系统内部来看,这不是你设计的一种拓扑结构,而是你转动的一个旋钮。在代码中,图只是线路;每个节点只是一个循环:
```
def fan_out(harness, worker, items):
# 每个(任务,切片)一个循环 Worker —— 每个都在自己干净的上下文中运行
return [harness.spawn(worker, task, material) for task, material in items]
```
图节点的设计规则:在生成它之前决定什么会回来。父上下文精确地增长返回值,所以你要先设计返回值。如果你不能用一句话说清楚回来的形状——一个数字、一个列表、一个裁决——你就没有画出边界,而是让账单翻倍。
一个你没有检查的返回答案只是更快的污染,所以图以一个检查器结束——而且它必须干净地运行,对产生它的工作没有任何忠诚度:

> "你甚至可能想要一个对抗性的……真的彻底折腾它,与已完成的工作没有任何同情关系。"

> "随着模型推理能力的提升,你可以用这些子代理来检查主代理的工作。"
```
def adversarial_verify(harness, artifact, rules):
def checker(ctx, tools, task, material): # ctx 是全新的;只看到 artifact
broken = rules(artifact) # 而不是它是如何制造的 —— 无可辩护
return "REJECT: " + "; ".join(broken) if broken else "ACCEPT"
verdict = harness.spawn(checker, "adversarially verify", repr(artifact))
return str(verdict).startswith("ACCEPT")
```
测试证明了这道关卡有牙齿——给它一个坏的合并,它就会拒绝。没有这最后一个节点的图只是一个有着更好图表的未验证系统。
## Layer 3 - THE HARNESS(挽具/运行环境)
上面两层一直在调用 harness.spawn(...)。这就是那个东西:所有代码在其中执行的运行时。工程师列出了里面有什么:

> "在 harness 里你有工具"

> "你在循环中运行的工具,然后你有提示词,最后是文件系统。文件系统是上下文工程的一种方式。"

> "研究、压缩、钩子、内存——它们也都是围绕 harness 的其他东西。"
“你在循环中运行的工具”。循环是 harness 的一个组件——这就是为什么这是一个堆栈,而不是三种竞争的技能。Harness 为你做两件事。
工作 1 - 让生成变得廉价。你思考生成什么,而不是怎么生成:

> "我们在 harness 里为你处理所有这一切,这样你就可以思考:我需要分出哪些子代理?"

> "当你运行并行子代理时……bash 会变得非常复杂——有很多竞态条件。我们在那里做了很多工作。"
而且它偏好一个通用工具,而不是一抽屉的定制工具:

> "如果你在设计一个 agent harness,你会需要一个搜索工具、一个 lint 工具和一个执行工具。相反,现在 Claude 就只用 grep。"
工作 2 - 保持每个 Worker 的上下文干净。这是承重方法,也是让隔离成为现实的一条规则:
```
def spawn(self, worker, task, material):
child = Context() # <-- 全新的,空的。不是 self.parent。
child.add(task); child.add(material) # 沉重的材料只进入 CHILD
result = worker(child, self.tools, task, material)
self.parent.add(str(result)) # 父级只增长结果
return result
```

> "主要的一点是避免上下文污染,所以你不想分叉上下文。你要启动一个新的上下文会话。"
把父窗口分叉进子进程,你什么也没隔离——你只是复制了混乱。子进程从空白开始,在自己的窗口里读取它的切片,交回一行。而当一群进程正在运行 bash 时,harness 的最后一层就是包含它的那一层:

> "最后一层是沙盒。假设有人恶意接管了你的 agent——它实际上能做什么?"
## 运行它,看着账单保持平稳
这就是流水线。自底向上:一个程序必须批准的循环,一个展开循环并检查其干净的图,一个让两者都变得廉价并保持其上下文隔离的 harness。./run.sh 打印证据:
```
HARNESS event log (parent context grows by RESULTS, not by sheets):
spawn #1: child_ctx=58B parent +71B (sum sheet: sheet-A)
spawn #2: child_ctx=57B parent +69B (sum sheet: sheet-B)
spawn #3: child_ctx=53B parent +72B (sum sheet: sheet-C)
spawn #4: child_ctx=81B parent +6B (adversarially verify)
parent (main-agent) context size: 218 bytes - it never held a full sheet.
```
处理了三份完整的表格。主 Agent 的上下文——每一轮你要为之付费的东西——最终只有 218 字节。不需要更大的窗口,不需要更好的模型。只需要带有返回类型的边界。这就是工程师反复强调的要点:

> "你应该永远不要把整个电子表格读入上下文,因为它会占用太多。"

> "这是我的第五次压缩。我想——什么?我以前几乎从没做过压缩。"
他几乎从不压缩,因为他几乎从不让窗口填满。这就是技能,现在它正在你的机器上运行。
## 接下来去哪里
演示生成器是脚本化的,所以它可以离线确定性地运行。把 src/workers.py 的 act 换成一个真实的模型调用,其他什么都不用改——loop、graph 和 harness 不知道也不在乎候选结果是谁产生的。这是对分层是否诚实的一次测试。
三个问题——边界在哪里,返回类型是什么,你怎么验证它。没有一个问题是这三个词里哪个该写进你的简介。
仓库:github.com/Archive228/loop-graph-harness —— 从干净的克隆运行 ./run.sh,9 个测试。完整的时间码到文件的映射在其 LECTURE.md 中。
## 相关链接
- [Archive](https://x.com/ArchiveExplorer)
- [@ArchiveExplorer](https://x.com/ArchiveExplorer)
- [3.6K](https://x.com/ArchiveExplorer/status/2080621294979023358/analytics)
- [github.com/Archive228/loop-graph-harness](https://github.com/Archive228/loop-graph-harness)
- [升级到 Premium](https://x.com/i/premium_sign_up)
- [7:49 PM · Jul 24, 2026](https://x.com/ArchiveExplorer/status/2080621294979023358)
- [3,608 次查看](https://x.com/ArchiveExplorer/status/2080621294979023358/analytics)
- [查看引用](https://x.com/ArchiveExplorer/status/2080621294979023358/quotes)
---
*导出时间: 2026/7/25 11:33:57*