Articles
Trust the Harness, Not the Agent

Trust the Harness, Not the Agent

I wrote that the smart move is to compose Claude Code and Hermes, then realized I had skipped the hard part. Composition is not a vibe, it is a mechanism. There are two ways to trust work that happens without you: invest in the agent, or invest in the process. Hermes does the first. The two tools I built, Stratum and Compose, do the second.

TL;DR. In the last Field Notes I said the smart move was to compose Claude Code and Hermes instead of picking a winner. That was true and also a dodge, because I never said what composition actually requires. There are two ways to trust an agent you are not watching. You can invest in the agent, which is the Hermes bet: cross-session memory, self-written skills, governance. Or you can invest in the process, which is the bet behind the two tools I built, Stratum and Compose: postconditions on every step, hard budgets, gates that block, and an audit trace you can read like a stack trace. The first makes the agent more trustworthy over time. The second makes the agent's trustworthiness irrelevant, because the work has to pass a check either way. I think you want both, and I think most people only build the first.

Last time I wrote about Claude Code and Hermes Agent, and I ended on what felt like a wise, balanced note: do not pick a winner, compose them. Use Claude Code to build the automation with taste and supervision, hand the recurring version to Hermes, and bring it back to the workshop when it breaks. I still believe that. I also reread it and noticed I had pulled a small trick on myself.

"Compose them" is not a plan. It is a verb wearing a plan's clothes. I described two tools, declared that they should work together, and then waved at the seam between them as if it were obvious. It is not obvious. The seam is the entire problem. The moment you let any agent do work while you are not looking, the interesting question stops being "which tool" and becomes "what makes me willing to trust the output of a process I did not personally watch run." I skipped that question. This post is me going back for it.

The Part I Hand-Waved

Here is the thing the rivalry framing hides, and the thing my own composition framing also hid. The hard part of agent work is not generation. It is not even orchestration, exactly. It is trust under absence. When I am sitting in Claude Code watching diffs, trust is cheap, because I am the check. I read the patch, I reject the clever part, I run the tests. The supervision is the safety. The instant the work moves somewhere I am not, that safety evaporates, and I have to replace it with something else.

In the last post I noticed this and then mostly admired the problem instead of solving it. I said Hermes "asks for my governance" and that "memory needs hygiene." Both true. Neither is a mechanism. You cannot ship hygiene. You ship code that enforces it or you do not have it.

So let me be more concrete than I was. There are two useful places you can put the trust when you remove yourself from the loop. You can put it in the agent, and try to make the agent more reliable over time. Or you can put it in the process, and try to make the work verifiable regardless of how reliable the agent happens to be on any given run. These are not the same bet. They are barely even the same philosophy.

Bet One: Trust the Agent

This is the Hermes bet, and I do not mean that as a knock. It is a coherent, ambitious wager. A persistent agent with cross-session memory is, at its core, an argument that reliability is something an agent accumulates. Run number seven is less dumb than run number one because the agent remembered the workaround, kept the preference you corrected twice, and reused the skill it wrote last week. The trust grows because the agent grows. You add governance around it (narrow credentials, channel boundaries, approval points, logging) and the combination of a smarter-over-time agent and tightening guardrails is supposed to add up to something you can leave alone.

I like this bet for a real class of work. Recurring chores, monitoring, webhook-driven jobs, the daily sludge that should keep moving while I sleep. For that, an agent that remembers and a few good boundaries genuinely is the right shape.

But I flagged the failure mode last time and then walked past it, so let me stop and stare at it now. The danger with a long-lived agent is drift. It accumulates assumptions. It keeps a workaround past its expiration date. It gets confident about a workflow whose environment changed quietly underneath it. Memory is the feature and memory is the liability, because the same mechanism that makes run seven smarter makes run seventy subtly, invisibly wrong.

And here is the uncomfortable part. Governance does not actually catch drift. Governance catches blast radius. Narrow credentials mean a confidently wrong agent does less damage. They do nothing to tell you that it is wrong. You can give an agent perfect permissions and a beautiful audit log of every action it took, and still have no idea that the third step of its nightly job has been quietly producing garbage for two weeks, because nothing in the system ever asked "is this output actually correct" in a way that could fail.

That is the gap. Trusting the agent scales the agent's competence and bounds its damage. It does not, on its own, verify the work.

Bet Two: Trust the Process

So I made the other bet. I should disclose this plainly, because the rest of the post is me describing two tools I wrote, and you should discount my enthusiasm accordingly: I built Stratum and Compose. They are the reason I have opinions about this at all, and they are also why I am the wrong person to ask whether you will like them. Take the design argument, not the salesmanship.

The bet behind both is the opposite of the Hermes bet. Instead of trying to make the agent trustworthy, assume it is not, and make the work checkable anyway. Move the trust out of the model and into the harness around the model. The agent can be brilliant or it can be having a bad day. The postcondition does not care. It either passes or it does not, and if it does not, nothing downstream gets to proceed.

Stratum: LLM calls that behave like the rest of your code

Stratum started from a small, annoyed observation. Everywhere I looked, LLM calls were the one part of the system that did not behave like code. A normal function has a type signature, raises on bad input, and shows up in a stack trace when it fails. An LLM call had none of that. It returned whatever, you wrapped it in a retry loop that just rolled the dice again, you bolted on a budget check and some logging, and debugging a failure meant reading a transcript instead of a trace.

The core move is two decorators with identical signatures. @infer marks a function the LLM executes. @compute marks a deterministic one. The caller cannot tell which is which. That sounds like a parlor trick until you realize what it buys: you can test your orchestration by swapping an @infer call for a @compute stub, and you can replace a flaky model step with a plain rule the day a pattern hardens, without touching any calling code. The LLM stops being a special citizen and becomes a function like any other.

Then you put the trust where it belongs, on the boundary:

@infer(
    intent="Classify sentiment",
    ensure=lambda r: r.confidence > 0.7,
    budget=Budget(ms=500, usd=0.001),
    retries=3,
)
def classify_sentiment(text: str) -> SentimentResult: ...

Three things in that block are the entire philosophy. The ensure is a postcondition, a plain Python lambda evaluated against the output, and when it fails the retry does not replay the prompt and pray. It injects the specific violation back ("confidence was 0.42, you need above 0.7, fix this") so the model gets targeted feedback instead of noise. The Budget is a hard ceiling on time and money, not a hint, and retries draw from the same budget, so there are no surprise bills hiding in a loop. The return type is a typed @contract, enforced at the token level by the structured-outputs API, which means the model cannot emit a label outside the enum or a confidence outside its range.

There is more underneath (a prompt compiler that makes every prompt inspectable and hashed, an opaque[T] type that passes one agent's free-text reasoning to the next as structured data so it cannot smuggle in instructions, await_human that genuinely suspends a flow until a typed decision comes back) but the shape is already clear from those three lines. The agent's judgment is no longer the thing standing between a bad output and your production data. The postcondition is. If you wrote the postcondition well, the worst the agent can do is fail loudly and retry.

Compose: the lifecycle as a runtime

Stratum makes a single step checkable. Compose is the layer above it, and it exists because of a sentence I wrote in the last post almost by accident. I described how a workflow moves through stages: first it is uncertain so I build it interactively, then it is understood so I automate it, then it breaks so I bring it back to the workshop. I wrote that as an observation. Compose is that observation turned into an executable lifecycle.

A feature in Compose moves through real phases, idea then design then blueprint then implementation, and between them sit gates that actually block. It dispatches multiple agents under competing mandates (one told to make the smallest possible change, another told to design it cleanly, a third to find the pragmatic middle) and a Codex review gate has to pass before the work advances. It is model-agnostic, it tracks artifacts, and it loops iterations across agents instead of trusting one agent's one pass. The whole point is that no single phase gets to declare itself done. Something else checks, and the something else is structural, not a vibe.

The two compose, naturally. Compose orchestrates the lifecycle, and the steps inside it are Stratum specs, so every step carries its own postconditions and the run produces an audit trace you can read after the fact like a stack trace, not a chat log. When I want the receipts for why a thing shipped, they exist, because the harness produced them as a side effect of doing the work.

Same Anxiety, Opposite Investment

Lay the two bets next to each other and the symmetry is almost too clean.

Hermes (trust the agent)Stratum + Compose (trust the process)
Where reliability livesIn the agent, accumulated over timeIn the harness, enforced every run
Core mechanismCross-session memory, self-written skillsPostconditions, budgets, gates, contracts
What you designAccess boundaries and approval pointsCorrectness boundaries (what must be true)
How you debugRead the transcript and the logsRead the structured trace and the failed ensure
Catches drift?No, governance bounds damage, not errorSometimes, for the invariants you assert (a changed prompt or contract hash is also a drift signal)
Failure modeConfidently wrong, quietly, for two weeksLoud and early, the step refuses to pass
Cost to youOperational responsibilityWriting the checks, and the ceremony of gates
Best atPersistence, reach, recurring autonomous workVerifiable correctness, repeatable builds, audit

Both are answers to the exact same fear, the fear that started this whole line of thinking: what happens to the work when I am not in the loop. Hermes answers it by making the absent agent smarter and better-boundaried. Stratum and Compose answer it by making the absence safer, because the work has to clear a check that does not depend on anyone being present to run it.

The drift point is where the two bets stop being symmetric and start being complementary. I said Hermes's signature danger is drift, and I stand by it. A good postcondition can act as a drift detector for the invariant it names, and a changed contract hash is a schema-drift signal. The thing Hermes does not get from memory and governance alone is a per-step correctness check, which is precisely what the harness exists to provide. Which is why I do not actually think these compete. I think the persistent agent is what you want running the workflow, and the harness is what you want wrapped around every step it runs, so that an agent that compounds knowledge over weeks cannot also compound a mistake over weeks.

What Annoys Me About My Own Tools

I am required by self-respect to be at least as hard on the things I built as I was on the things I did not.

A postcondition only catches what you thought to assert. This is the real limit of the trust-the-process bet, and there is no way around it. ensure=lambda r: r.confidence > 0.7 checks that the model is confident. It does not check that the model is correct. If I do not write the check, the harness happily passes work it never examined, and now I have a false sense of safety, which is worse than an honest absence of one. Writing good postconditions is work, it is the same skill as writing good tests, and most people will not do it well by default. The harness does not remove the human bottleneck. It relocates it from watching diffs to specifying truth, and specifying truth is harder.

Compose has the opposite failure mode, which is ceremony. A lifecycle with gates is only as good as the gates, and a gate you rubber-stamp is theater with extra steps. The first time you wave a Codex review through because you are in a hurry, you have converted a safety mechanism into a delay you resent. Process trust is real trust only when the process can actually say no and you actually let it.

And neither tool makes taste optional. I said last time that taste is still a human bottleneck, and I will say it again louder, because the trust-the-process bet can fool you into thinking you have automated judgment when all you have done is encode the judgment you already had. The encoding is valuable. It is not the same as having more of it.

How I Actually Choose

If the work is recurring, latency-tolerant, and mostly free of aesthetic judgment, I want a persistent agent running it, and Hermes-shaped autonomy is the right reach. If the work has a correctness boundary I can state, anything where I can write down what must be true for the output to be acceptable, I want it wrapped in postconditions and budgets so the boundary is enforced and not merely hoped for. If the work is a multi-stage build that needs to be repeatable and auditable, I want a lifecycle runtime with gates, so no phase gets to grade its own homework.

Most real work is more than one of those, which is the same conclusion as last time, just earned this time instead of asserted. Build it with supervision in Claude Code. Wrap each step in a harness so correctness is checked and not assumed. Let a persistent agent run the verified thing when presence would be a waste. And when it drifts, the harness is what tells you, early and loud, instead of the customer telling you, late and angry.

The Real Lesson

The rivalry framing was a trap because it asked me to pick between tools good at opposite jobs. My own composition framing was a softer trap, because "compose them" sounded like wisdom while quietly skipping the mechanism. The mechanism is this: decide where the trust lives before you remove yourself from the loop. In the agent, or in the process. Most agent discourse, including mine until I caught it, invests almost entirely in the agent, makes it smarter, gives it memory, wires it to every channel, and then bolts on guardrails and calls the trust problem solved.

I do not think it is solved. I think a smart agent with bad postconditions is a confident, well-spoken way to be wrong at scale, and I think the least glamorous part of all of this, writing down what must be true and refusing to proceed when it is not, is the part that actually earns the right to walk away. Trust the harness. The agent is the part that does the work. The harness is the part that lets you leave.