<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Agent-Harness on ENKR's Blog | Jing Hui PANG</title><link>https://blog.enkr1.com/tags/agent-harness/</link><description>Recent content in Agent-Harness on ENKR's Blog | Jing Hui PANG</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>ENKR</copyright><lastBuildDate>Mon, 31 Aug 2026 18:00:15 +0800</lastBuildDate><atom:link href="https://blog.enkr1.com/tags/agent-harness/index.xml" rel="self" type="application/rss+xml"/><item><title>Agents Are Mostly Plumbing: Reading DeepSeek's Open-Source Harness</title><link>https://blog.enkr1.com/agents-are-mostly-plumbing/</link><pubDate>Tue, 18 Aug 2026 12:43:08 +0800</pubDate><guid>https://blog.enkr1.com/agents-are-mostly-plumbing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;someone dropped the deepseek-harness link in front of me with the only question that matters about a new repo: does this help my work. i went in expecting another coding-agent clone, cloned it, counted it, and came out with a different question entirely, because the interesting part turned out not to be the agent. i had my AI do the cloning, the line counting and the pressure-testing of my reading. the personal note at the bottom is mine to write after.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="tldr"&gt;tl;dr
&lt;/h2&gt;&lt;p&gt;deepseek open-sourced its agent harness (&lt;code&gt;dsh&lt;/code&gt;) on 13 august 2026. MIT, typescript, 226 packages, about 272,000 lines of product code once you drop the tests. the model-facing adapter layer is &lt;strong&gt;3.3 per cent&lt;/strong&gt; of that. everything else is session logs, tool pipelines, sandboxing, approval policy, context compaction, an lsp client and a web ui. the useful moves for an engineer are to &lt;strong&gt;read it&lt;/strong&gt; and possibly to &lt;strong&gt;embed it&lt;/strong&gt;. the ones that look tempting and are not: switching your daily driver to preview software, or joining the plugin gold rush five days late.&lt;/p&gt;
&lt;h2 id="the-question"&gt;the question
&lt;/h2&gt;&lt;p&gt;the honest question about any new tool is never &amp;ldquo;is this good&amp;rdquo;. almost everything is good. the question is whether it beats the thing it would replace by enough to pay for the switch, which is the whole argument in &lt;a class="link" href="https://blog.enkr1.com/curation-beats-collection/" &gt;curation beats collection&lt;/a&gt;. i went in ready to run that test, decide no, and move on.&lt;/p&gt;
&lt;p&gt;then i counted the lines, and the switching question stopped being the interesting one.&lt;/p&gt;
&lt;h2 id="most-of-an-agent-is-not-the-agent"&gt;most of an agent is not the agent
&lt;/h2&gt;&lt;p&gt;here is where 272,000 lines of an actual, shipped, frontier-lab agent harness go.&lt;/p&gt;
&lt;figure style="margin:1.6rem 0"&gt;
&lt;svg viewBox="0 0 620 300" role="img" aria-label="Where the lines of code go in an open-source agent harness" style="width:100%;max-width:620px;height:auto;font-family:inherit;display:block;margin:0 auto"&gt;
&lt;text x="310" y="20" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor"&gt;Where the code actually goes in an agent harness&lt;/text&gt;
&lt;text x="310" y="36" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.6"&gt;DeepSeek Harness, lines of TypeScript excluding tests&lt;/text&gt;
&lt;text x="222" y="60" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.8"&gt;web UI (browser client)&lt;/text&gt;
&lt;rect x="232" y="44" width="274.0" height="24" fill="#3b82f6" fill-opacity="0.8" rx="2"/&gt;
&lt;text x="514.0" y="60" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;113,470 (42%)&lt;/text&gt;
&lt;text x="222" y="98" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.8"&gt;platform, host, type graph&lt;/text&gt;
&lt;rect x="232" y="82" width="125.1" height="24" fill="#3b82f6" fill-opacity="0.8" rx="2"/&gt;
&lt;text x="365.1" y="98" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;51,796 (19%)&lt;/text&gt;
&lt;text x="222" y="136" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.8"&gt;agent loop, subagents, skills, hooks&lt;/text&gt;
&lt;rect x="232" y="120" width="107.3" height="24" fill="#3b82f6" fill-opacity="0.8" rx="2"/&gt;
&lt;text x="347.3" y="136" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;44,435 (16%)&lt;/text&gt;
&lt;text x="222" y="174" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.8"&gt;tools: fs, shell, sandbox, lsp, mcp&lt;/text&gt;
&lt;rect x="232" y="158" width="69.4" height="24" fill="#3b82f6" fill-opacity="0.8" rx="2"/&gt;
&lt;text x="309.4" y="174" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;28,724 (11%)&lt;/text&gt;
&lt;text x="222" y="212" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.8"&gt;session log, history, compaction&lt;/text&gt;
&lt;rect x="232" y="196" width="58.2" height="24" fill="#3b82f6" fill-opacity="0.8" rx="2"/&gt;
&lt;text x="298.2" y="212" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;24,119 (9%)&lt;/text&gt;
&lt;text x="222" y="250" text-anchor="end" font-size="11.5" fill="currentColor" fill-opacity="0.95"&gt;model adapters (the LLM bit)&lt;/text&gt;
&lt;rect x="232" y="234" width="21.8" height="24" fill="#f97316" fill-opacity="0.95" rx="2"/&gt;
&lt;text x="261.8" y="250" font-size="11.5" fill="currentColor" fill-opacity="0.85"&gt;9,017 (3%)&lt;/text&gt;
&lt;line x1="232" y1="38" x2="232" y2="264" stroke="currentColor" stroke-opacity="0.45" stroke-width="1.2"/&gt;
&lt;text x="310" y="292" text-anchor="middle" font-size="12" fill="currentColor" fill-opacity="0.85"&gt;total: 271,561 lines across 226 packages&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption style="text-align:center;font-size:0.85rem;opacity:0.7;margin-top:0.5rem"&gt;Lines of TypeScript by concern, tests excluded. The browser client dominates because a harness needs somewhere to be used from. The model adapter, the only part that is arguably about AI, is the smallest bar on the chart.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;look at the bottom bar. the part that talks to a language model, the adapters, the streaming vocabulary, the retry logic, all of it, is 9,017 lines. three per cent.&lt;/p&gt;
&lt;p&gt;and notice what has no bar at all: there is no prompt-engineering bucket, because there is barely any prompt engineering. the system prompt gets one package that assembles sections and tool schemas. that is it. the thing people imagine an AI product &lt;em&gt;is&lt;/em&gt;, the clever prompt, does not show up as a rounding error.&lt;/p&gt;
&lt;p&gt;what does show up is the stuff nobody demos. an append-only session event log so a conversation survives a reload. a query layer over that log, with a sqlite backend. compaction, for when the history outgrows the window, including a model-free pruner that throws away stale tool results without paying for a summarisation call. a scoped tool registry with a guarded execution pipeline. a sandbox with landlock on linux. an approval policy with permission presets. filesystem, shell, subprocess, terminal, lsp and mcp adapters. a job scheduler. attachment storage. credential storage that is write-only from the ui.&lt;/p&gt;
&lt;p&gt;that list is the actual product. the model is a dependency it calls.&lt;/p&gt;
&lt;p&gt;this is the reframe i did not expect: &lt;strong&gt;building something agentic is mostly a systems-engineering job, not an AI job.&lt;/strong&gt; if you have been putting off agent work because you do not have ML background, the line count says the ML background was never the blocker. the blocker is that you have to build a durable event log, a permissions model and a sandbox, and those are boring, and boring is expensive.&lt;/p&gt;
&lt;h2 id="no-privileged-core-and-what-that-buys"&gt;no privileged core, and what that buys
&lt;/h2&gt;&lt;p&gt;the architectural bet has a slogan, &amp;ldquo;everything is a plugin&amp;rdquo;, and one line in the architecture doc that actually explains it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is no privileged core to patch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;the framework underneath is &lt;a class="link" href="https://github.com/cordiverse/cordis" target="_blank" rel="noopener"
&gt;cordis&lt;/a&gt;, where plugins contribute services, typed events and reversible effects to a shared context. so the model adapter is a plugin. the tool registry is a plugin. the session log is a plugin. the agent loop itself is a plugin. a running instance is a plugin tree composed at boot from ordered layers: bundles stack in order, then a profile patch, then a home-level patch, then a command-line overlay. any row the tree prints can be replaced by a patch of your own.&lt;/p&gt;
&lt;p&gt;what that buys is real. you want a different persistence backend, you swap the row. you want your own model adapter for a company gateway, there is a documented seam and a guide for writing one. you want to intercept every tool call, that is an extension point rather than a fork. the reversibility matters too: registrations unwind when their plugin unloads, so hot-swapping is a design property rather than a hack.&lt;/p&gt;
&lt;p&gt;what it costs is also real, and the repo does not hide it. everything being a seam means nothing is a shortcut. there are 226 packages, and to change behaviour you first have to find which of the 226 owns the thing you want, then learn cordis, then learn the patch layering. the docs are excellent and there are a lot of them, which is itself the tell: this is a framework with a learning curve, not a library you drop in.&lt;/p&gt;
&lt;p&gt;the &lt;a class="link" href="https://blog.enkr1.com/build-vs-buy/" &gt;build versus buy&lt;/a&gt; crossover applies exactly. the fixed cost here is learning the composition model. it pays back only if you are going to keep composing.&lt;/p&gt;
&lt;h2 id="four-ways-an-engineer-can-actually-use-it"&gt;four ways an engineer can actually use it
&lt;/h2&gt;&lt;p&gt;ranked by how certain the payoff is, which is not the order people reach for them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. read it as a reference architecture.&lt;/strong&gt; highest certainty, lowest cost, and almost nobody does it. if you are building anything agentic, someone has now published a working answer to every question you are about to hit, under a licence that lets you copy the shape. how do you replay a session deterministically for tests (&lt;code&gt;llm-replay&lt;/code&gt;). how do you prune context without a summarisation call (the tool-result pruner). how do you scope a tool registry so a subagent cannot see the parent&amp;rsquo;s tools. how do you gate an action behind human approval without the loop knowing about approval. the &lt;code&gt;docs/subsystems/&lt;/code&gt; folder is one file per problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. embed it as a runtime.&lt;/strong&gt; the part most people miss, because the repo is presented as a coding agent. there is a &lt;code&gt;headless&lt;/code&gt; profile that mounts no server and no ui at all: one task in, one answer out, exit code for whether it finished. there is a typescript sdk and a python sdk that drive a harness runtime from another process. there is an &lt;a class="link" href="https://agentclientprotocol.com/" target="_blank" rel="noopener"
&gt;agent client protocol&lt;/a&gt; server for talking to it programmatically. so if you are building a product that needs an agent inside it, the choice is not &amp;ldquo;write my own loop&amp;rdquo; versus &amp;ldquo;call the api in a while loop&amp;rdquo;. you can take the whole harness, session log and tool pipeline and sandbox and approval gate included, and drive it from your own service. that is a year of plumbing you do not write.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. extend it instead of forking it.&lt;/strong&gt; if it does 90 per cent of what you need, the seam model means the last 10 per cent is a plugin, and your plugin survives upstream changes in a way a fork does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. run it as your coding agent.&lt;/strong&gt; the least interesting use, and the one every take is about. worth knowing: it is genuinely model-agnostic in practice, not just in architecture. deepseek gets a first-class card in settings, but there is a catalog provider path for anthropic, openai, bedrock, vertex, azure, and a custom-provider form for a company gateway or a self-hosted endpoint. and there are compatibility bridges that read your existing claude code hooks and codex hooks, though the readme is refreshingly blunt that the bridge is a migration path and a native plugin would be strictly better.&lt;/p&gt;
&lt;h2 id="they-shipped-the-decision-record-too"&gt;they shipped the decision record too
&lt;/h2&gt;&lt;p&gt;the thing i did not expect to find, and the thing i would point a junior engineer at first.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.agents/notes/&lt;/code&gt; contains 693 design notes, sorted by lifecycle: 515 implemented, 142 archived, 25 proposed, and &lt;strong&gt;11 rejected&lt;/strong&gt;. they published the proposals they turned down, and the stated rule for keeping a rejected one is that it should stay only while its rationale still prevents a tempting mistake. there are five numbered postmortems in &lt;code&gt;docs/&lt;/code&gt;. there is a set of their own internal agent skills, including one called &lt;code&gt;dsh-trim-cot-leakage&lt;/code&gt;, which is a skill for stripping chain-of-thought leakage out of the codebase, which tells you exactly how this thing was built and what it took to clean up after.&lt;/p&gt;
&lt;p&gt;most open-source repos give you the code and lose the argument. this one shipped the argument. for anyone learning how large systems actually get decided, that folder is worth more than the 272,000 lines it explains, and it rhymes with the reason i keep writing these notes at all: the reasoning is the durable part, the artefact is downstream of it.&lt;/p&gt;
&lt;h2 id="where-people-get-this-wrong"&gt;where people get this wrong
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;&amp;ldquo;get in early on the plugin ecosystem.&amp;rdquo;&lt;/strong&gt; it is not early. five days after launch there were 6,862 repos carrying the &lt;code&gt;dsh-plugin&lt;/code&gt; topic. more to the point, the obvious categories are already saturated and already worthless: i counted at least nine separate plugins whose pitch is &amp;ldquo;bring your claude code config into dsh&amp;rdquo;, and they were sitting at eight stars, six, five, two, one, one. everybody had the same idea in the same week and the market paid none of them. if you are going to build something here, the crowded shelf is the one you can see from the readme.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;contribute to it.&amp;rdquo;&lt;/strong&gt; you cannot, at least not upstream. the contributing guide says plainly that they cannot accept external pull requests at the moment. twenty-four contributors, three pull requests, all internal. the sanctioned path is building in the ecosystem, which is the crowded shelf above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;153,000 stars means it is good.&amp;rdquo;&lt;/strong&gt; star velocity measures attention, and a big well-documented repo appearing suddenly from a well-known lab generates a lot of it. nobody has run this in production yet. the repo is five days old on the day i am writing this and it has 226 packages, which means it was developed privately for a long time and dropped, so the code is mature and the &lt;em&gt;operational&lt;/em&gt; evidence is zero. those are different things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;i should switch to it.&amp;rdquo;&lt;/strong&gt; the repo tells you not to, if you read it. it calls itself a developer preview and warns of compatibility-breaking changes. the session format version is pinned at 0 with no compatibility promise. the agents file has a section, marked for deletion at the first tagged release, instructing contributors to prefer the correct foundation over compatibility shims because there are no external consumers yet. that is an honest statement that your data is not safe here. i had the same instinct once before and talked myself out of it for a similar reason, in &lt;a class="link" href="https://blog.enkr1.com/almost-switched-ai-agent-memory/" &gt;the note about almost switching my agent&amp;rsquo;s memory&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-verdict"&gt;the verdict
&lt;/h2&gt;&lt;p&gt;read it, maybe embed it, do not marry it.&lt;/p&gt;
&lt;p&gt;as a daily driver it fails the switch test, and it says so itself. as a plugin business it is a crowded shelf you would be arriving at late. as a reference architecture it is the most complete public answer to &amp;ldquo;what is actually in an agent harness&amp;rdquo; that i know of, and it costs an afternoon. as an embeddable runtime it is a genuine option worth a spike if you are building a product with an agent inside it, on the understanding that you are pinning a version and expecting to eat migrations.&lt;/p&gt;
&lt;p&gt;and the finding underneath all of it, the one that survives even if this particular repo is abandoned in six months: the model is three per cent. if you are an engineer looking at agent work and assuming the hard part is the AI, the code says the hard part is the systems engineering you already know how to do.&lt;/p&gt;
&lt;h2 id="a-personal-note"&gt;a personal note
&lt;/h2&gt;&lt;p&gt;wip &amp;hellip;&lt;/p&gt;
&lt;h2 id="sources-and-further-reading"&gt;sources and further reading
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;the repo: &lt;a class="link" href="https://github.com/deepseek-ai/deepseek-harness" target="_blank" rel="noopener"
&gt;deepseek-ai/deepseek-harness&lt;/a&gt;, MIT licensed. start at &lt;code&gt;docs/architecture.md&lt;/code&gt;, then &lt;code&gt;docs/subsystems/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/cordiverse/cordis" target="_blank" rel="noopener"
&gt;cordis&lt;/a&gt;, the plugin framework underneath, and the &lt;a class="link" href="https://github.com/cordiverse/paper" target="_blank" rel="noopener"
&gt;paper&lt;/a&gt; describing its composability model.&lt;/li&gt;
&lt;li&gt;all counts in this note were taken from a shallow clone on 18 august 2026, excluding &lt;code&gt;*.spec.ts&lt;/code&gt; and &lt;code&gt;*.test.ts&lt;/code&gt;. star and topic counts came from the github api the same day.&lt;/li&gt;
&lt;li&gt;my &lt;a class="link" href="https://blog.enkr1.com/curation-beats-collection/" &gt;curation beats collection note&lt;/a&gt;: why a new tool has to beat the incumbent, not just be good.&lt;/li&gt;
&lt;li&gt;my &lt;a class="link" href="https://blog.enkr1.com/build-vs-buy/" &gt;build versus buy note&lt;/a&gt;: the crossover that decides whether learning a framework pays back.&lt;/li&gt;
&lt;li&gt;my &lt;a class="link" href="https://blog.enkr1.com/boris-cherny-claude-code-workflow/" &gt;summary of boris cherny&amp;rsquo;s claude code tips&lt;/a&gt;: the other side of this, how to use a harness rather than how one is built.&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>