My harness development workflow had a name. It was called bob, and I killed bob in July.
bob was built the way you build things when you don’t trust the tool yet. Prescriptive gates everywhere. Mandatory steps in a fixed order. Checks that ran whether or not there was anything to check. Every lesson I learned got encoded as another rule, and the rules only got updated as a concious improvement loop. It worked, in the sense that it produced usually solid code. It also spent an enormous amount of effort proving to itself that it had done its job. For Gemini 3.1 and Opus 4.6, it did a really good job.
Then Anthropic published prompting guidance for Opus 5, and one paragraph landed hard:
If your prompt contains explicit verification instructions (“include a final verification step for any non-trivial task,” “use a subagent to verify”), remove them: instructions like these cause over-verification on Claude Opus 5, and removing them reduces wasted tokens with no loss in quality. The same applies to legacy harness scaffolding that adds separate verification steps.
That’s bob. That’s the entire design philosophy of bob, named as an antipattern in the vendor docs. So I wanted to find out what happens if I actually follow the guidance instead of arguing with it.
The replacement is called root. It’s been running against my main work codebase for about around 2 weeks.
The shape of it
Five stages. The main workflow lives in a skill with one file per stage, and the top-level file is ninety lines. There are a few specific subagents as well.
Plan with a human in the loop. This is the only part where I’m required. I work with the agent to trace the actual code, not the issue summary, and we land on a GitHub issue and a committed plan document. The issue is the requirements doc. The plan is the delta on it: what changes, what for, and what done means. It records the decisions and what they were chosen over, because six weeks later the second half is what you actually need. The planning doc goes into the OKF-style wiki in the codebase.
Turn the plan into a graph. This is the most complex stage and the one where improvement pays the most. The graph is nodes with dependencies, and each node carries an intent (the brief), an acceptance (what done means), and a writes set. Everything else is bookkeeping.
The writes field is the part I’d tell anyone to steal. Dependencies are semantic: what must land before this makes sense. They tell you nothing about whether two nodes can safely share a checkout. Inferring parallelism from dependencies is a proxy, and it fails in both directions. Two unrelated nodes can still collide. Two dependent nodes are often fine to overlap once the first has committed.
So I write the real answer down. writes is every path a node dirties, including the ones nobody types:
| A node that | also writes |
|---|---|
| adds or bumps any dependency | the root lockfile, always |
| touches the Prisma schema | the migrations directory, the generated client |
| adds a workspace package | root package.json, tsconfig references, lockfile |
| regenerates a fixture | the whole snapshot dir, not just the test |
All of that is knowable while you’re writing the graph. None of it is knowable from reading an agent’s report afterward. Two nodes may share a checkout only if their write sets are disjoint. Where they are disjoint, run them concurrently even if a dependency links them. That single rule is most of the speed.
Put it to a council. Three judges, one per model family, and none of them share the family of the agent that wrote the plan. A model favors its own output; that’s not a moral failing, it’s just a thing you design around. They read the issue, the plan, and the graph, and answer one question: is this going to produce the right software?
Each judge writes its verdict to disk before I answer any of them. The record is append-only. If a judge changes its mind after the rebuttal, it has to state the change against its own original objection, not “you explained it.”
One rebuttal round, maximum. More rounds hurt even as more judges help. If two rounds can’t resolve it, the plan is insufficient and it goes back to me. Two standing dissents stop the run. One doesn’t, except on the deny list (auth, billing, migrations, the display render path) where any single dissent stops it. The asymmetry is deliberate: I’m one person, and I recover from a missed design flaw next commit. A false alarm costs me an hour of attention on a plan that was fine.
Drain the graph. Two agents per node, one commit per node, review before the commit. The specialist implements and signals ready. A read-only reviewer on a different model family critiques and changes nothing. The main loop (named as a ‘foreman’) arbitrates, and sends the updates back to the main agent. The specialist reconciles and commits. This is the human-in-the-loop check point. It’s also one rebuttal maximum. So if the reviewer, foreman, and specialist can’t get on the same page with one round of edits, the glass breaks and I step in. This is likely because a deeper or different issue was uncovered in the code and/or the plan.
We’re on a worktree for the draining process. So we can set it off to the side and dig deeper into another branch if we need to for issue resolution.
The reviewer prompt is adversarial by question, not by verdict. Not “were the criteria met” but:
- What did the old code guarantee that this no longer does?
- What input makes this behave differently from what it replaced?
- Which branch of the old control flow has no home in the new one?
- What does this claim that a passing build does not prove?
And I ask it to report everything it finds, ranked, with whatever evidence it has. That’s straight from the same Anthropic guidance: telling a reviewer to be conservative makes it report less. The foreman who has the entire plan and graph in context is the filter. Not the reviewer.
The commit is the gate. Pre-commit runs lint, type-check, and the tests in changed packages. Not a separate verification stage, not a subagent that double-checks. The specialist that wrote the code owns the red and fixes it. My evidence is the green commit and the diff.
That’s the whole inversion. bob had gates because I didn’t trust the agent. root has one gate, and it’s the same gate a human contributor hits.
The migration was excruciating
I want to be honest about this part, because the finished thing reads much cleaner than the process felt.
Building a meta-harness inside Claude is genuinely disorienting. You’re talking about code, except you’re not. You’re talking about the thing that talks about the code. Half my sessions went sideways because the agent thought I wanted to fix a bug in the app when I wanted to fix the rule that decides who fixes bugs in the app. Then it would helpfully edit the harness mid-run, which invalidates the entire run, which I then had to write a rule about. (root is not edited during a run. A failure after that point is attributable to nothing.)
There was a lot of typing in all caps. There was cursing. There were rabbit holes I’m still slightly embarrassed about.
The failure mode I keep coming back to is that I’d encoded my own anxieties as process, and deleting bob didn’t delete the anxieties. They came along. I wrote them back into root without noticing, in gentler language, because they still felt like diligence.
The clearest example showed up in an early root build. The foreman loop developed a testing fetish. It ran a 6,000-test suite fourteen times for a sixty-line changeset. Nothing was wrong. It just kept looking, because I’d carried forward a rule that said verify, and the v5 models take that instruction seriously and then apply their own judgment on top of it. Compounding, not redundant.
That one hurt, because it happened in the thing I’d built specifically to not do that.
That’s the thing the docs are actually warning about. The scaffolding doesn’t just waste tokens. It teaches the model that the work isn’t trustworthy, and then the model behaves accordingly.
What I’m getting out of it
It’s finding things. That’s the short version.
Edge cases and finicky little race conditions that had been sitting in the codebase for months. The kind of bug that doesn’t fail in CI and doesn’t fail in staging and then bites hard in production on a Tuesday. A resumed agent grabbing a checkout another node was mid-edit on. A switch statement with no exhaustiveness assertion, so adding an enum value compiles clean and silently drops the case. Those aren’t glamorous finds. They’re exactly the ones I’d have shipped.
The other thing: I’m getting work done again. Through the worst of the migration I was building the machine instead of using it, which is a well-known way to spend a month. That’s coming in for a landing. The harness is stable enough now that I mostly think about the issue, not about the pipeline.
There’s more to do. The graph stage is still the weak point, and it’s where I’ll spend the next round of effort. The council is expensive and I don’t yet have a clean rule for when to skip it beyond the deny list. I’ve got a second iteration running against a different codebase, and the two are already diverging in ways I need to reconcile.
I’m also working through what the equivalent best practices look like for the Gemini model families. The guidance is different enough that I don’t think you can just port a harness across, and I’d rather say something useful about that later than something confident about it now. When that workflow matures, I’ll write it up.
But I’m starting to like my new framework. That’s more than I could say about bob for a long time.
The part that generalizes
If you’ve built your own harness and it’s full of gates, the honest question is which of those gates has ever caught anything. That’s a rule I put in root explicitly: no gate that has never caught anything, and no field without a consumer that reads it.
Most of my scaffolding existed because a model failed me once in early Paleolithic (of AI) and I never went back to check whether it still would. The tools got better. My rules didn’t improve at the same pace. Following the vendor’s actual guidance felt like giving up control, and it turned out to be the opposite. Fewer rules, better placed, and a single real gate at the end.
The tools change. The craft endures. But sometimes you do have to put the old tools down.