SherlockLiu Logo SherlockLiu
Back to all posts
Engineering

What a Second Production Harness Teaches (Part 15)

SL
Aug 14, 2026 10 min read
What a Second Production Harness Teaches (Part 15)

Series: Inside the DeepSeek Harness — Part 15 of 16


Fourteen posts ago, this series opened with a promise: read DeepSeek Harness the way April’s Agent Harness series read Claude Code — as a worked example, not a verdict. Both series exist to answer the same question: how do you turn a stateless model into something that plans, acts, recovers, and remembers? Claude Code and dsh land on genuinely different answers, built by different teams under different constraints, and the disagreements are exactly where the real lessons live.

This post is that comparison, problem by problem, followed by the five ideas I’d actually carry into a project regardless of which architecture I picked.


The comparison, problem by problem

Problem Claude Code’s answer dsh’s answer
What’s the core loop? One hardened, purpose-built harness ReactLoopAgent — a plugin like any other, replaceable from config (Part 9)
Tool permissions A dedicated permission pipeline Monotonic deny-only guards + a separate approval phase, both stacked on the same waterfall primitive that runs everything else (Part 4)
Configuration Settings files, layered by scope Five ordered YAML patch layers resolved by one pure merge function, inspectable via --dump-config (Part 2)
Memory / context A dedicated memory system The session log itself — one append-only event stream, with a runtime-enforced invariant that the model can never see more than the log can reconstruct (Part 6)
Context compression Dedicated compression logic A replace surface op over the same log — nothing is ever rewritten, only shadowed (Part 7)
Extensibility A hook system Five Cordis dispatch modes, and one waterfall pattern doing most of the real work — the same mechanism guards, retries, and compaction all run through (Part 8)
Multi-agent work Subagents, coordinators, skills A named-provider registry with four provider kinds, plus a structurally distinct “continuable” category for anything that needs to be steerable and resumable (Part 11)
Streaming A dedicated streaming architecture One canonical StreamChunk protocol and one shared assembler every provider adapter feeds (Part 10)
Plan mode A dedicated plan-mode system Soft, logged, per-agent state attached through the same agent/pre-step waterfall as everything else — the loop has zero built-in knowledge that “plan mode” exists at all
Agent specialization Four hardcoded agent types — Explore, Plan, General, Verify — compiled into the binary Four presets: directories holding agent.cordis.yml, mounted per session; a fifth is a duplicate RPC away, no fork required (Part 16)

Look at the right-hand column as a whole and a pattern jumps out immediately: dsh keeps re-deriving specific behaviors from a small number of general primitives (Context, Service, Fiber, waterfall, the append-only log), rather than building a dedicated subsystem per problem. Claude Code, so far as the April series documented it, tends toward more purpose-built machinery per concern. Neither approach is strictly better — a purpose-built subsystem can be more directly optimized for its one job; a small set of general primitives, reused everywhere, means one fix or one insight (a waterfall() bug fix, say) improves every consumer at once, not just one subsystem.


The one structural bet that explains almost everything else

If you take one idea from this entire series, it’s the sentence Part 1 opened with: there is no privileged core. Not “the core is small.” Not “the core is well-tested.” There isn’t one — the agent loop itself is a plugin, swappable from the same YAML patch mechanism that swaps a sandbox provider. Every other comparison in the table above is downstream of that one bet. A tool pipeline that’s “just” a waterfall chain, a memory system that’s “just” an event log, a plan mode with zero special-cased loop support — all of it falls out of committing, completely, to the idea that nothing in the product gets to be exempt from the plugin discipline everything else follows.

That’s also, I think, the honest answer to whether “rival to Claude Code” was ever the right frame for this series, back in Part 1. It isn’t really a competition between two products. It’s two different, well-reasoned answers to “should anything in an agent harness be structurally privileged” — and watching both answers get built out in real, shipping code is more interesting than declaring a winner.


Six ideas worth stealing, regardless of which architecture you pick

1. Make “model-visible” and “logged” the same runtime check, not two separate design docs. Part 6’s invariant.ts — a listener that derives the expected request from the log and throws on divergence — is the single most portable idea in this whole series. It doesn’t require Cordis, or plugins, or any of dsh’s specific machinery. Any agent harness with a durable history can add this exact check in an afternoon, and it converts “the log is the source of truth” from an aspiration into something that actually fails loudly the moment it stops being true.

2. Give every capability the same three-role shape. Service Definition, Provider, Consumer, with an explicit resolve(request): Spec step instead of a hidden default — Part 5’s pattern. You don’t need ~85 of them to get the benefit; even a handful of capabilities (model provider, tool executor, storage backend) built this way pays for itself the first time you need to swap one in a test environment.

3. Derive internal policy state from the log instead of keeping it separately. Part 10’s retry counter — scanned from durable llm/retry events instead of held in memory — was the single cleverest mechanism this series found. It’s the same idea as #1, applied one level down: if your system already has a durable log, ask what else you’re tracking in memory that could just be derived from it instead.

4. Write down what you tried and rejected, not just what you shipped. Part 9’s cancellation bug fix, with four explicitly rejected alternatives and why each one broke, was better engineering writing than most postmortems manage. It’s a cheap habit — one paragraph per rejected approach — that pays off every time someone reaches for the same “obvious” fix again next year.

5. Report orthogonal outcomes independently. Part 5’s ShellRunResult (timedOut, aborted, signal, exitCode, all independent) and Part 12’s denial-vs-runner-failure classification are the same defensive pattern twice. Any time you’re tempted to collapse a result into one status field, ask whether two of the facts you’re encoding can actually be true at the same time — if they can, they need to be independent fields, or you will eventually misreport one as the other.

6. The unit a user can copy should be the same unit your team ships. Part 16’s presets are the clearest instance of this in the series: an “agent mode” is a directory, so duplicate is the entire authoring surface, and a copy can never carry more capability than what it copied. It’s the reason a same-day plugin ecosystem was even possible. If your harness’s specialized behaviors live as compiled branches instead, nobody outside your team can ever add one — measure that cost deliberately, not by default.


A lens worth borrowing: pre-emptive vs. post-hoc control

It’s worth borrowing a framing from harness-engineering discussions outside this series: Guides, controls that stop a bad action before it happens, and Sensors, controls that catch a bad outcome after it already did. It’s a clean way to re-read almost everything in this series’ comparison table. dsh’s guards (Part 4) are Guides — deny-only, pre-execute, structurally unable to let something through that shouldn’t happen. The session-log invariant check (Part 6) is a Sensor — it can only throw after a divergence already occurred, never prevent one. Both series lean on both kinds, and neither kind is optional: a harness with only Guides can still silently drift from its own invariants; a harness with only Sensors catches problems after damage is already logged. The four classic ways an agent fails without either kind of control catching it — stopping before the goal is met, acting blind to its actual environment, self-reporting success it didn’t achieve, and forgetting instructions a fresh context never carried forward — are a good checklist for whichever harness you’re auditing, this one or your own.

That framing also sharpens the honest gap in both harnesses’ comparison table above: neither dsh nor Claude Code, so far as either series has verified in source, ships a strong answer to acceptance — checking that the agent did the right thing, not merely a permitted one. Guards and permission pipelines are Guides for authorization. Invariant checks and hooks are Sensors for state consistency. Nothing in either codebase plays that role for task correctness. Part 12’s PM-0003 postmortem is what happens in that gap: every automated signal the agent had — a 200 response, a green build — said success, and the agent was still wrong.


What I’d still want to know

A few things this series couldn’t answer from the outside, worth naming honestly. Real production load — the postmortems in Part 12 are genuine, but they’re a developer-preview’s worth of incidents, not years of scale. Whether the plugin-everywhere bet holds up as the package count keeps growing past ~150 — more indirection generally means more places for a subtle bug like PM-0001’s export default mistake to hide, even with the coverage discipline Part 14 documented. And the actual adoption question this series’ Part 1 opened with: whether an open harness that works with any model actually grows the ecosystem the way DeepSeek’s pricing strategy is betting it will, or whether Claude Code’s tighter, single-vendor integration ends up mattering more to most builders than architectural elegance does.

None of that changes what’s true about the code itself, which is what this series actually set out to verify: real primitives, real invariants enforced at runtime, real incidents with real fixes, cited down to the file and line. If you’re building your own harness, both series — this one and April’s — are worth reading as a pair. Not for which one to copy. For the difference between them, which is where the actual engineering judgment lives.


The full series

Part Title
1 DeepSeek Harness: Inside the Open-Source Claude Code Rival
2 Composing an App From YAML, Not Code
3 Scope: Why a Live Agent Is the Key of Its Own Registration
4 Tool Execution in DeepSeek Harness: Guards and Approval
16 DeepSeek Harness: Agent Presets as Data, Not Code
5 Capability Seams: Making Bash Swappable for Sandboxed Bash
6 The Session Log: DeepSeek Harness’s Enforced Invariant
7 Persistence and Compaction: Crash-Safe by Construction
8 Waterfalls: The One Event Pattern That Runs Everything
9 The Agent Loop: Turns, Steps, and a Real Cancellation Bug
10 The LLM Layer: One Message Format, Every Surface
11 Subagents and Workflows: Composing Agents From Agents
12 Defense in Depth: Sandboxing and Four Real Incidents
13 Three Surfaces, One Spine: Web, Typert RPC, and SDK/ACP
14 Engineering Rigor: DeepSeek Harness’s Verification Gate
15 What a Second Production Harness Teaches (this post)

References

  • DeepSeek AI, deepseek-ai/deepseek-harness — the repository this entire series is built from, pinned throughout to commit 47f9438
  • This blog’s Agent Harness series (12 parts, April 2026) — the Claude Code case study this series is read against
  • This blog’s How Claude Code Is Designed series (6 parts, March 2026)
  • Part 16 — Agent Presets, PTC, and the plugin ecosystem, added after this series’ initial publication once Agent Presets and Code Mode shipped
  • Every prior post in this series, each with its own file-and-line citations back to the real source

Comments