EN 中文
← Blog

Harness, Loop, Graph: How My System Grew One Layer at a Time

A need pulls the concept out.

Three buzzwords

Harness is the engineering wrapped around the model: tools, permissions, sessions, persistence. The model supplies judgment; the harness supplies hands and memory. The Claude Code CLI is a harness. A model without one is just a chat box.

Loop is an agent that stays alive: wake → read state → do the work or delegate it → sleep, round and round. I run two loops: Nerve handles every project, Helm handles company operations. Each has run continuously for two months on cron wakeups, on-disk memory, and watchdogs that heal them. The interesting part is that Helm doesn’t even route through me — it receives WeChat messages and handles them itself. That is deliberate, because my own head really is short on capacity.

Graph is wiring several nodes — agents, deterministic code, human approvals — into an explicit topology: nodes doing the work, edges handling the routing, state flowing between them. In mid-July people on Twitter hyped it into “Graph Engineering,” but LangGraph has been doing it for over two years. What actually changed is this: a node used to hold nothing braver than a few parallel subagent calls, and now it can hold a complete, complex multi-agent flow.

Evolution wasn’t designed

In chronological order: first the harness (hands for the model), then people made agents live longer (loop), then work a single loop couldn’t finish had to be split across several agents (graph). Mapped onto my own stack: Claude Code is the harness, Nerve and Helm are the loops, Dynamic Workflow is the graph. There is a whiff of concept-chasing about that, admittedly. But by the time the community started arguing about the word in July, I had already run 356 graph runs in the previous 14 days, 93% completion, median execution time 7 minutes.

Claude Code’s built-in dynamic workflow is itself a graph, but only half of one: it is disposable — the loop mints one on demand, discards it after use, leaves a journal behind, and can replay it exactly from cache. What I think you want is the improved version: a named graph. That is the real one — long-lived, reusable, versioned (@vN, versions kept in git). Under a $200/month subscription where you cannot call the API freely, reworking DW is the relatively optimal way to do graphs at all.

A Spectator

Over the last couple of days I wrapped a larger observer loop around my several loops, called Spectator. Anyone who has played Minecraft gets it instantly: spectator mode — fly through walls, see everything, touch nothing. The reason is that a loop cannot notice its own problems; it cannot be Gödel-complete about itself. This is structural: when the referee and the athlete are the same person, the result usually disappoints.

Spectator is one independent session, waking every 3 days, reading only the exhaust pipes of the other two loops (transcripts, DW journals, logs, pm2). It has exactly one core move: take what the system claims it did and check it against what actually exists. It writes nothing to the systems it observes. Nerve and Helm don’t even know it exists.

So the system splits into three planes: control (me plus approvals), execution (loops plus graphs), observation (Spectator). Three planes, three tempos: execution runs in hours, observation in days, and I set direction on a slower beat than either. This is not a new invention — cybernetics calls it an observer, corporate governance calls it audit independence, aviation calls it the NTSB. The only new part is wiring it to an autonomous LLM system. Very few people in the agent world do this, for a very practical reason: most agents don’t survive an hour, so there is nothing to audit, and under per-API billing, keeping a non-productive observer alive is pure overhead. A Max-plan subscription flips that math — the marginal cost of the observer is roughly zero.

What it saw

Spectator’s first batch of data (14-day window):

  • The long session went through 48 compacts (context compression restarts). In-cycle error rate, early/mid/late = 4.25% / 4.21% / 3.73% — the “35-minute performance decay” from the literature is not measurable in this architecture. Discretizing on wake plus on-disk memory really does hold off context rot.
  • 35 graphs launched in the last 10% of a context window, right up against the compact, ran to completion anyway — straight across the compact boundary. Graphs survive independently of the context that launched them; this is the first time that architectural advantage has been quantified.
  • The unflattering results too: only 63% of the artifacts a graph claims for itself can be verified; and the iron rule that “every dead run must be redone” has a measured compliance rate of 40%. A rule written in a document is not a rule that gets executed — which is exactly what the next step has to fix.

What I’m building

The direction in one line: compile the doctrine into mechanism. Rules written in markdown keep the direction only; anything that should happen every single time sinks down into schemas, templates, and driver scripts. Six concrete pieces: agent return values must carry an artifact manifest (a schema contract); dead runs revive automatically (turning that 40% into a mechanical guarantee); logs get schematized, with an author field; named workflows carry version numbers (@vN, versions tracked in git, the journal recording which one each run used); the publishing pipeline gets compensation logic (better to publish nothing than to publish to the wrong surface); and a fixed task set runs as a nightly regression bench. All of it fits inside the subscription constraint, because my harness already ships every tool required: the journal is the checkpointer, schema validation is the typed state transition.

The endpoint is letting the graph modify itself: the regression bench scores it → a new topology version gets drafted → anything that scores worse is blocked → anything better comes to me for approval. The precondition is that the brakes go in first — versioning and an independent observation plane are the brakes, and both are already in place.

Why I only built it once Opus 5 shipped

It isn’t that I only just thought of it; it’s that I only now think it’s worth doing. A model’s harness has to match the capability of the model itself. Opus 5 has now drawn level with Fable and Mythos on capability, and it is cheap enough to actually use — so changing the architecture follows naturally. Opus 4.8 could write a graph, but the cognitive load was heavy and it couldn’t use one well: a graph’s quality ceiling is its nodes’ quality ceiling. When the nodes aren’t stable enough, topology failures and node failures are indistinguishable, all the effort you spend on structure gets eaten by node noise, and you end up wrongly concluding the architecture was the problem. Once Opus 5 shipped, “one node = one complete agent” finally holds, and investment in structure starts to pay.

The community line is right: graph engineering isn’t new. What’s new is that the nodes are finally worthy of the graph.

Harness、Loop、Graph:我的系统是怎么一层层长出来的

需求引出概念。

三个 buzzword

Harness 是模型外面那圈工程:工具、权限、session、持久化。而模型供判断,harness 供手脚和记忆。Claude Code cli 就是一个 harness。没有 harness 的模型只是一个聊天框。

Loop 是活着的 agent:wake → 看状态 → 干活或派活 → 睡觉,循环往复。我有两个 loop:Nerve 管全部项目,Helm 管公司事务,各自连续跑了两个月,靠 cron 唤醒、磁盘记忆、watchdog 自愈。有意思的是Helm 办公甚至不经过我——微信消息自己收自己处理,这是故意设计的,因为我的脑容量实在有限。

Graph 是把多个节点(agent、确定性代码、人类的审批)连成显式拓扑:有节点干活,负责路由的边界,有流动的状态。7 月中旬 Twitter 网友把它炒成了 “Graph Engineering”,其实 LangGraph 已经做了两年多。真正变了的是:以前节点里只敢subagent 平行的子模型调用,现在能放一个完整多agent复杂流程图。

进化不是设计出来的

先有 harness(给模型手脚),然后有人让 agent 活得久(loop),然后 loop 一次干不动的活需要拆给多个 agent(graph)。对应的是:Claude Code 是 harness,Nerve/Helm 是 loop,Dynamic Workflow 是 graph。虽然有炒概念的嫌疑。等社区 7 月开始吵吵这个词的时候,我这边最近 14 天已经跑了 356 个 graph run,93% 完成度,执行时间中位数 7 分钟。

Claude Code 内置的 dynamic workflow 本身就是一个 graph,但它只是一个半成品:它是一次性的,loop 按需铸造一张,用完即弃,journal 留痕,要恢复可以从缓存精确重放。我认为你需要的是改进版:named graph,它才是一个真正的 graph——常驻、可复用、带版本号(@vN,git 管版本)。在每月 $200 订阅、不能随意调 API 的约束下,改造dw 是玩graph的相对最优形态。

一个Spectator

我这两天在我的几个loops上面套了个大的观察者loop,叫Spectator,玩过Minecraft的可以秒懂,旁观者模式——穿墙飞行看得见一切,碰不到任何东西。原因是Loop 本身意识不到自己的问题,做不到哥德尔完备,是结构性的:自治系统裁判和运动员是一个人的时候,结果往往都不尽人意。

Spectator,他是一个独立 session,每 3 天醒一次,只读两个 loop 的排气管(transcripts、DW journal、log、pm2),核心动作只有一个:拿“系统声称做了什么”去对“现实里有什么”。它对被观测系统零写入,Nerve 和 Helm 甚至不知道它存在。

于是系统分成三面:控制面(我 + 审批),执行面(loops + graphs),观测面(Spectator)。三面三种节律:执行面以小时计,观测面以天计,我以更慢的节奏定方向。这不是啥新发明——控制论里叫 observer,公司治理里叫审计独立性,航空里是 NTSB。新的只是把它接到自治 LLM 系统上。Agent 圈很少人这么做,原因很实际:大部分 agent 活不过一小时,用不着审计;API 计费下养一个不产出的观察者是纯 overhead。而 max plan订阅制把这笔账翻转了——观察者的边际成本约等于零。

观察到了什么

Spectator 上线第一批数据(14 天窗口):

  • 长 session 经历了 48 次 compact(上下文压缩重启)。周期内错误率 early/mid/late = 4.25% / 4.21% / 3.73%——文献里的“35 分钟性能衰减”在这个架构里测不到。wake 离散化 + 磁盘记忆确实防住了 context rot。
  • 最后 10%context临近compact 才发起的 一共35 个graph,都能跨过 compact 边界照样跑完。图独立于发起者的上下文存活,这个架构优点第一次被量化。
  • 不尽人意的也有:graph 自称的产物只有 63% 能验真;“死掉的 dw 必须重做”这条铁律,实测执行率 40%。规则写在文档里不等于规则被执行——这正是下一步要修的东西。

在建什么

方向是:把教义编译成机制。md规则只留方向,凡是“每次都该这样做”的,下沉进 schema、模板、驱动脚本。具体有六点:agent 返回值强制带产物清单(schema 契约);死掉的dw自动复活(把 40% 变成机制保证);log schema 化,加author;named workflows 带版本号(@vN,git 管版本,journal 自动记录每次跑的是哪版);发布流水线加补偿逻辑(宁可发不出,不发错面);夜间固定任务集回归测试。全部在订阅约束内完成,因为我的 harness 已经内置了所需的全部工具:journal 就是 checkpointer,schema 校验就是类型化状态转移。

终点是让graph自己改自己:回归测试打分 → 起草新版拓扑 → 分数变差的拦住 → 变好的我批准。前提是有刹车——版本化和独立观测面就是刹车,两个都已经在了。

为什么 Opus 5 出来才建

不是现在才想到,是我觉得现在才值得做。模型的harness 是要和模型本身能力匹配的。现在opus5 能力上追平 fable/mythos,又便宜能用,自然而然就要改架构。之前Opus 4.8 写得出 graph,但认知负担大,用不好 graph:图的质量上限就是节点的质量上限。节点不够稳的时候,拓扑失败和节点失败分不开,你花在结构上的功夫全被节点噪音吃掉,最后误以为是架构错了。Opus 5 出来,“一个节点 = 一个完整 agent”才真正成立,结构的投入才开始有回报。

社区那句话说得对,graph engineering 不新鲜。新的是模型终于配得上了。