DeepSeek Harness Isn't a Gimmick — It's an Agent Runtime That Chose Trustworthiness Over Performance
Introduction
I got fed up with the DeepSeek Harness hype a few days ago. Twitter, YouTube, WeChat official accounts, tech forums — it was everywhere, with headlines more sensational than the last: "Kill Claude Code," "DeepSeek Just Killed Proprietary Coding Agents." I glanced at the repository, and it already had 177K stars (still climbing faster than I can type as I write this). A project labeled Developer Preview, version still at 0.1.1-rc.1, hitting this scale in a week — that's interesting.
First, let's clarify what it is. DeepSeek Harness is an agent harness, the shell wrapped around a large model: the model does the thinking, and the harness makes it read files, run commands, call tools, and get the job done step by step. Claude Code and Cursor all have this underneath. These shells are everywhere now; most are just a CLI wrapped around a chat API with a flashy name. I assumed this was another overhyped gimmick, so I went straight to the source code. And I have to say, I actually found something.
1. What Makes an Uncertain LLM-Driven System Trustworthy?
I was initially drawn in by the "everything is a plugin" marketing slogan, so I was interested in seeing how its plugin system was designed. But while reading the source, a piece of code in the agent-loop caught my attention:
ctx.on('llm/stream', (options: GenerateOptions, next) => {
if (!isAgentLoopRequest(options)) return next()
if (!Object.isFrozen(options)) fail('a loop-built request must be frozen')
if (options.sessionId === undefined) fail('a loop-built request must carry a session id')
const session = ctx.sessions.get(options.sessionId)
if (!session) fail(`... must carry a live session id ...`)
if (!Object.isFrozen(options.messages)) {
fail('a loop-built request must carry a frozen messages array')
}
// ...several pre-checks omitted...
const expected = session.deriveMessages()
if (JSON.stringify(options.messages) !== JSON.stringify(expected)) {
fail(`llm request ... diverges from the dispatch-time durable derivation (log-reconstruction desync)`)
}
// ...then field-by-field comparison of model / system / temperature / tools...
}, { global: true, prepend: true })
This code is hooked onto llm/stream, the exact moment before each request is sent to the model. It doesn't generate any content, doesn't call any tools; it does one thing: intercept the request right before it goes out, run a round of verification, and if anything is off, it calls fail, crashing the entire call.
What exactly is it verifying? The core is these two lines:
const expected = session.deriveMessages()
if (JSON.stringify(options.messages) !== JSON.stringify(expected)) fail(...)
options.messages is the content about to be sent to the model. expected is the content re-derived from the session log using deriveMessages(). The two are compared as full strings via JSON.stringify. If they don't match, it reports a log-reconstruction desync and throws an exception immediately.
To understand the weight of this line of code, you need to understand what it's fighting against. Anyone who has worked on LLM systems knows that the most direct way to root-cause an online issue is to reconstruct the scene: what exactly was fed to the model at that moment? So you go check the logs. But the log you find was recorded at the moment of instrumentation, and before the request is actually sent, the content often goes through several more hands — assembling system prompts, stuffing in conversation history, truncating overly long contexts, injecting dynamic information. What's recorded in the log and what the model actually received can be two different things. You spend ages trying to reproduce the issue based on the log, only to find that what you reproduced might not be what happened at all.
This piece of DSH code mandates that what can be derived from the log and what is actually sent to the model must match byte-for-byte, or it won't send. This way, the log is no longer an approximate record but an exact replica of the scene, perfectly solving the problem of reconstructing the field.
2. Is This DSH's Innovation?
The underlying principle of re-deriving a request from a log is event sourcing: instead of storing request snapshots, you store atomic events and fold them to reconstruct state when needed. This is a decades-old concept, perfected by workflow engines like Temporal. During replay, the generated command sequence must match the history command by command; any mismatch throws a non-determinism error (official docs), enforced at runtime. Temporal has been doing this for years.
But here's the interesting part: this strict verification is standard in general-purpose workflow engines but rare in agent frameworks.
Take the most mainstream comparison. LangGraph is the most widely used agent orchestration framework right now. It has a checkpointer and supports time-travel replay. But if you read its official documentation, it states: during replay, nodes will re-execute — LLM calls and API requests will actually be sent again, and the returned results might differ from the original. In other words, LangGraph's replay only guarantees that the input state of each step can be restored, not that the reconstructed content matches what the model actually saw at the time, and there is no runtime verification to enforce this. Determinism relies entirely on the developer being careful when writing code.
This isn't to say LangGraph is bad; most agent frameworks are in this same state. But it makes us realize: logs that can precisely reconstruct the request the model saw are not the default choice in the agent world.
DSH brings the strictness of a Temporal-level workflow engine into the agent runtime: it not only stores event streams and projects requests, but before every single request is sent, it spends extra overhead to pull the projected and the actual to-be-sent together for a full comparison, and crashes immediately on mismatch. This level of rigor is genuinely rare among similar agent projects.
3. Is This Level of Rigor Worth It?
Self-checking every request incurs significant overhead. Is it really worth it?
- It's added to the hottest path:
deriveMessages()must fold the entire event stream; the longer the history, the more expensive it gets.JSON.stringify-ing a context of tens of thousands of tokens and then comparing strings isn't free either. The longer the context (when you most want to save costs), the more expensive this check becomes. - It guards against bugs in its own code: Under what circumstances would the projected content differ from the sent content? Only when DSH's own code (or a plugin's) has a bug. So why not just write the logic correctly, cover it with unit tests and the type system, and make every online request pay a performance tax for your bugs?
- The implementation isn't elegant either: Using
JSON.stringifyfor a full comparison is sensitive to key order. If adesyncis reported, it only tells you there's a mismatch, not where, leaving you to troubleshoot on your own.
These doubts are all valid. And the question of whether such runtime assertions should be enabled in production has long been settled by the industry, with a fairly one-sided answer: in most cases, they shouldn't be. The default posture of mainstream projects is assertions are only enabled during development and testing, and turned off in production builds. The most typical evidence is the Percona incident at the end of 2025: they mistakenly shipped a PostgreSQL build with assertions enabled into production sources, and the official announcement urged everyone to upgrade immediately, citing that assertions cause 20%–50% performance degradation and can cause production outages by killing processes via fail-fast. Running runtime assertions on every critical operation in production is a minority practice in the mainstream, even considered an incident.
So which domains insist on keeping runtime checks on in production? Databases and compilers — domains where correctness is more precious than performance. They share a common trait: continuing to run with corrupted internal state has far worse consequences than crashing outright.
Looking back at DSH with this in mind, it becomes clear: it actively places itself in the "database, compiler" category, not the "ordinary online service" category. Whether this is reasonable depends on whether it truly belongs there.
Personally, I think it does. Because it's fundamentally an agent runtime, where the bottleneck is the model's inference time of several to tens of seconds. Spending a few extra milliseconds on projection verification is basically noise, imperceptible to the user. Unlike high-concurrency services, where a 20% overhead is deadly. More crucially, its entire raison d'être is reproducibility, auditability, and replayability. For such a system, a discrepancy between the log and the scene is a fatal bug. If it occurs and goes undetected, all your replays, debugging, and audits are fake. Add to that its core philosophy of "everything is a plugin" — third-party plugins can replace model adapters and session storage. Code written by others can too easily introduce inconsistencies. This check guards not just against its own team, but against anyone in the entire open ecosystem.
So the conclusion is: whether it's reasonable depends on the design perspective you take. From the perspective of a high-concurrency transaction system, it's over-engineering. From the perspective of a correctness-sensitive system like a database or compiler, it's good design.
Old A's comment: What I appreciate most isn't the code itself, but the value hierarchy behind it — willing to pay the overhead of a self-check on every single request rather than allow any chance for untrustworthiness to occur.
Another detail is that this assertion is registered with { global: true, prepend: true }. The comment in the source reads:
// Prepend prevents a short-circuiting replay listener from silencing the check.
Cordis events have waterfall semantics; if a middleware doesn't call next(), subsequent listeners are short-circuited. If someone registered a replay listener that short-circuits and it was placed before this check, the check would be silently skipped without you even knowing it didn't run. So they prepend the check to the very front and add global, effectively preemptively blocking the path where a future plugin might inadvertently bypass the check.
4. Why Is This Projection the Correct One?
By now, you might have a question: why is the content projected by deriveMessages() the correct one? What if it calculates wrong?
Look at the comment in packages/core/session/src/surface.ts. I found the wording quite deliberate on first reading:
This is THE per-node projection rule: Session.deriveMessages folds it over the live surface, external reconstructors and pure projections fold the same function over a log prefix's surface to rebuild the exact messages any request was built from.
It emphasizes one thing: there is only this one projection rule; a second set is not allowed. This is the core of the entire design, and what truly sets it apart from frameworks where replay does not guarantee consistency.
As mentioned earlier, LangGraph's replay re-calls the LLM. Why can't it reconstruct the exact same request as before? The root is here: once the online assembly of a request and the offline reconstruction of a request do not run the same code, even if both sides are written correctly initially, as soon as one side changes a boundary condition during iteration and the other side doesn't keep up, they will slowly drift apart.
DSH leaves no room for drift from the source: there is only one projection function, folded by both online and offline paths. The same function, two paths — what's sent online and what's reconstructed offline cannot structurally be two different things. So the assertion in section one verifies a relationship that should be inherently identical, and this inherent identity is upheld by the fact that there is only one projection rule.
This function also does something else: it clearly distinguishes which parts of the log are for the model to see, and which are for humans to see. The comment states it plainly:
turn/step boundaries, chunks, usage, and errors are trace/replay data.
Things in the log fall into two categories:
One category is for the model — like the assembled conversation content, what the model actually needs.
The other category is for humans — like streaming output chunks, token usage, error records, step boundaries. These are all noise to the model but are treasures for humans troubleshooting issues, replaying scenes, and conducting audits.
So the design deliberately splits into two paths:
The log is responsible for recording everything — useful or not, store it first, ensuring you can look up anything later.
The projection function is responsible for selectively feeding — each time it needs to feed the model, it only pulls out the part the model truly needs from the log, filtering out all the rest.
The key is that this projection function is the only one in the entire project. There is no situation of running one set online and another set for offline reconstruction. So one log is enough: it records comprehensively and feeds precisely, with the two goals not conflicting.
5. The Hardest Part: The Log Cannot Be Changed, but History Must Become Shorter
Up to this point, the entire design rests on one premise: the log is append-only. But the context window is finite; history must eventually be compressed. Compression means deletion, and deletion breaks the append-only design. This is the hardest part of the entire design to make self-consistent.
I specifically looked into how its compaction handles this problem, in packages/compaction/compaction/src/checkpoint.ts:
const COMPACT_CHECKPOINT_MARKER = Object.freeze({ kind: 'plugin', plugin: 'compact' } as const)
export function compactCheckpointSource(
compactionId: CompactionId,
sourceCommandId?: CommandId,
): CompactionCheckpointSource {
return Object.freeze({
...COMPACT_CHECKPOINT_MARKER,
compactionId,
...sourceCommandId === undefined ? {} : { sourceCommandId },
})
}
The idea is simple: append a replacement message with a source marker to the append-only log. Use COMPACT_CHECKPOINT_MARKER to indicate I was produced by the compact plugin, attach a unique compactionId, and optionally include the sourceCommandId of which command triggered it. The original history — not a single entry is deleted.
The cleverness here lies in:
Identifiable: This message carries a marker and won't masquerade as a normal model message mixed into the history.
Traceable: compactionId plus sourceCommandId makes who triggered this compaction and why queryable.
Doesn't break the foundation: All original events are preserved. The model sees a shortened history after projection; humans and tools can still access the complete long history.
The essence of this design is somewhat like a red-ink reversal in accounting: when a ledger entry is wrong, you can't erase it; you can only record another entry with a clear reversal annotation. The ledger is forever append-only, but the balance is correct. The model's context becomes shorter, but the system's memory doesn't — these two things are decoupled.
And it connects seamlessly with the previous section: because the projection rule is unique, how the compressed history is utilized by the model is also dictated by deriveEventMessage. Compaction doesn't bypass projection; it is itself one of the inputs to projection. There won't be a fork where online compaction runs one logic and offline reconstruction runs another. The projection rule remains the only one.
6. What Truly Changed My Mind Was What It Rejected
Everything before this is ultimately about what it built. Building can be packaged. What truly made me look at this project with new respect was the contents of the .agents/notes/ directory.
DSH has also made its decision-making process a system with a lifecycle.
Four status directories: proposed, implemented, rejected, archived. I counted: over 1600 files under implemented, over 30 in rejected, over 400 in archived, and over 70 still in proposed. Under implemented, it's further subdivided into architecture, bug-fix, feature, simplification, testing.
Most teams' Architecture Decision Records (ADRs) only record what we decided to do. Approved solutions are written into documents; rejected solutions are at most mentioned in an alternatives section, and more commonly scattered across chat logs, with no one systematically keeping records.
Old A's comment: This is the same logic as the previous section. The code doesn't delete history from logs, and the team doesn't delete history from decisions. When a project's technical philosophy aligns with its collaboration style, it usually means one thing: this is a philosophy the team collectively follows and believes in, not something put on for outsiders.
I'm not trying to blindly praise this directory's design. Some proposals in rejected/ were cut purely due to priority or scope, unrelated to trustworthiness. But under rejected/simplification/, there are two rejected optimization proposals. Both times, between simplicity and trustworthiness, they chose trustworthiness.
The first, drop-durable-step-boundaries.md. Someone proposed: let's delete the step/start and step/end step boundary events. After all, each event itself carries {turn, step} numbers. Boundary events produce no model-visible content; they are pure redundancy. Deleting them makes the log smaller and the code cleaner.
Sounds reasonable. But this proposal was rejected. The rejection reason, verbatim:
step/end is concrete information: a reader can tell whether a model request finished, crashed, or is being repaired without deriving that state from the next event.
Translation: step/end is concrete information. Without it, what you see in the log is a request started, and then nothing. You can't tell if it finished normally, crashed, or is being repaired and retried. These three states are worlds apart, but they look identical from the log surface.
That note also has a final section called "What we give up":
That loss is not acceptable while the session log is the durable replay and audit surface.
As long as the log is the basis for replay and audit, this loss of information is unacceptable. What the proposal wanted to delete was precisely the part useless to the model, and the rejection reason was precisely that it's useful to humans.
Old A's comment: This optimization proposal was actually very tempting. Deleting events that don't produce model input makes the log smaller, the code simpler, the logic purer. Many teams might have approved this proposal. And their reason for rejecting it was just one sentence: the person reading the log needs to be able to tell if it ended, crashed, or is being repaired. Judging whether an optimization should be done isn't based on what benefits it brings, but on what harms it brings.
The difference between redundancy and robustness often only manifests the moment something goes wrong, and by then, you have no choice left.
The second is even more typical, assembled-assistant-messages-only.md. Proposal: only store the assembled assistant messages, throw away the intermediate streaming chunks, save storage. Obviously, the assembled complete message is just all the chunks concatenated; storing both is indeed redundant.
Also rejected. Reason: losing chunks means you can never precisely reconstruct the token stream of an old turn; a stream that fails midway will have its partial output permanently lost; and high-fidelity replay and snapshot testing all depend on persisted chunks.
In reality, what's redundant isn't the data, but the capability. A stream that fails midway doesn't even have an assembled complete message; it only has half-finished chunks. Deleting chunks is equivalent to deleting all failure scenes together, and failure scenes are the very parts most needed for reproduction. This ties back to section one: that assertion demands byte-level identity, and this precision can only be built upon the original chunks. Cut the chunks, and the foundation of section one is gone.
Of course, these two notes aren't meant to prove every DSH decision is correct. It's still 0.1.1-rc.1, and the official team itself has stated there will be breaking changes. They only prove one thing: when simplicity and trustworthiness collide, what this team's default choice is.
7. Final Thoughts
Back to the opening question: DeepSeek Harness at 177K stars — gimmick or substance?
On the marketing side, clickbait and exaggeration definitely exist. Titles like "Kill Claude Code" — just take them as entertainment. But after digging through the source code, I genuinely think DSH's design has real substance.
What's valuable isn't the slogan "everything is a plugin," nor the benchmark scores. It's: an assertion that runs before every single request, a projection function that forbids a second set, a compaction like a red-ink reversal, and a directory storing rejected proposals.
The uncertainty of LLMs cannot be eliminated, and DSH doesn't try to eliminate it. What it does is confine the uncertainty to a single point: the model's output can be uncertain, but what the model saw must be 100% certain, reconstructable, and comparable. Uncertainty is isolated to one point, and the rest of the system remains deterministic.
This approach isn't actually scenario-specific. Any system that needs to reconstruct the scene after the fact can use it: critical contracts enforced by runtime assertions; online and replay sharing the same projection function; and the habit of asking, before proposing can this be optimized or deleted, to think carefully: after optimization, what will I look at when things go wrong?
Back to the opening question: Is DSH a gimmick? I think the marketing is. But its real value isn't in those hype accounts; it's in: an assertion that runs before every single request, a projection function that forbids a second set, a compaction like a red-ink reversal, and a directory storing rejected proposals. For these alone, among those 177K stars, I count my own vote.
Top 1 of 2 from juejin.cn, machine-translated. The original thread is authoritative.
Last week I also dug through the DSH repo. One more observation: the version number 0.1.1-rc.1 is right there, and the author clearly knows it's still a ways off from production readiness. The real problem is that the marketing set expectations way too high. When people actually get their hands on it and find the plugin ecosystem and stability lagging, it's DeepSeek's own reputation that takes the hit. For agent frameworks, slow and steady wins the race.
So I'm not recommending anyone use it in their projects. I'm just analyzing its design philosophy from a different angle.