DEV Community

Evan Lin for Google Developer Experts

Posted on Originally published at evanlin.com on

[AI in Practice] Same Name, Different Layer: DeepSeek Harness (DSH) Explained and Compared with Google Research Harness2

DeepSeek Harness vs. Google Research Harness²: two different layers

DeepSeek Harness (DSH) Google Research Harness²
In one sentence The agent's runtime An automatic optimizer for what the agent is equipped with
What "harness" refers to The runtime that executes the agent The prompts, guardrails, memory, and skills wrapped around the model
What you change Profiles, YAML patches, plugins The c1..c8 file tree (though usually Harness² changes it for you)
Where it's used in this series The agent layer of the LINE research bot Self-evolution of the LINE AI business-card assistant

Introduction: two "harnesses" in one week

In my recent Harness² trilogy (Part 1, Part 2, Part 3), I connected Google Research's google-research/harness2 to my LINE AI business-card assistant, letting it read OpenTelemetry traces and grow its own skill files. Accuracy climbed from 62.5% all the way to 100.0%.

This week I also came across DeepSeek's open-source deepseek-ai/dsh-superagent-prototype, which is built on DeepSeek Harness (DSH). I migrated the agent layer of my LINE research bot from ADK for Go to DSH, producing kkdai/line-research-bot-dsh, which is now running in production.

Both are called Harness, and at first I assumed they were the same kind of thing. After actually using both, it turns out:

DSH is about how the harness is assembled and strapped onto the horse so it can run; Harness² is about automatically adjusting every strap on that harness. They live at different layers and can even be combined.

Because there is a lot to cover, I split this into two posts:

  1. This post: what the DSH framework actually is (with an architecture diagram), and a point-by-point comparison with Google Harness².
  2. The next post: how I actually migrated the LINE research bot from ADK to DSH, plus a list of pitfalls.

1. Understanding DeepSeek Harness (DSH)

Many people assume dsh-superagent is an agent SDK. In fact, it consists of two separate layers:

Layer What it is On npm
DeepSeek Harness (DSH) An "agent runtime" that handles model calls, tools, sessions, permissions, and sandboxing, all implemented as plugins @deepseek-ai/dsh (CLI), plus 100+ @deepseek-ai/dsh-* packages
dsh-superagent A bundle (plugin pack) running on DSH that turns it into a proactive agent that works on a GitHub repository A Node package installed into a DSH profile via dsh plugin add

1.1 Core design: everything is a Cordis plugin

DSH is built on Cordis (@deepseek-ai/cordis), a plugin framework. Models, tools, session storage, sandboxing, even the JSON-RPC server: every piece is a plugin (a "plugin row"), and plugins communicate through services exposed on ctx, such as ctx.llm, ctx.tools, ctx.fs, and ctx.subprocess.

How plugins are composed is determined by a Profile:

  • Bundle: an official, pre-assembled set of plugins, e.g. dsh-sdk-minimal, dsh-base, web, tui, headless.
  • Profile: lives under $DSH_HOME/profiles/<name>/ and specifies which bundles to load.
  • Patch layers: YAML patches layered on top of bundles. A patch can change a plugin's config, disable it with disabled: true, or insert your own plugins. Run dsh --profile x --dump-config to see the fully resolved tree.
# Example patch: tweak model settings, disable the shell, insert a custom plugin
- id: llm-deepseek
  config:
    thinking: disabled
- id: persistent-bash
  disabled: true
- insert:
    - id: line-research-tools
      name: 'file:///app/dsh/plugin/index.js'

Enter fullscreen mode Exit fullscreen mode

1.2 DSH architecture

DeepSeek Harness (DSH) architecture

Four key facts follow from this diagram:

  1. The agent runs in a separate process. Unlike ADK's runner.Run(), which runs inside your program, with DSH you spawn a dsh runtime subprocess and talk to it over stdio JSON-RPC. The TypeScript client is @deepseek-ai/dsh-sdk-client; a Python SDK is also available.
  2. The model layer only speaks the Anthropic Messages protocol. The official adapter, llm-deepseek, targets https://api.deepseek.com/anthropic by default. You can change baseURL, but the other side must be a /v1/messages-compatible endpoint. There is no Gemini adapter.
  3. Tools are registered by plugins. You write a Cordis plugin and call ctx.tools.register(defineTool({...})) inside apply(ctx). DSH validates arguments against the parameter schema; on failure, the error is returned to the model so it can correct itself.
  4. A session is an event stream. Every run() returns the full list of session events: turn/start, tool/call, tool/result, assistant/message, turn/end, and so on. Both structured output extraction and debugging rely on these events.

1.3 What dsh-superagent builds on DSH

dsh-superagent is a prototype of a "proactive coding agent" used internally by the DeepSeek team. Its README is explicit: it is a research prototype, not a production product. Its domain model looks like this:

dsh-superagent domain model

  • A Source converts GitHub notifications and Feishu messages into Triggers.
  • Eval decides whether to accept a job based on Policy (who can issue commands, where, and with what authority). Accepted work becomes a Ticket.
  • Each Ticket is handled by an Executor Session working in its own directory. Results flow back to the original conversation through a Channel, e.g. by opening a PR.
  • A web dashboard shows which items need a human decision.

Its execution model is a single long-running process + SQLite + a management API that listens only on 127.0.0.1, and it requires a GitHub repo and an agent account. That is why, when migrating the LINE bot, I borrowed only DSH and did not fork dsh-superagent; details are in the next post.

💡 Takeaway: When talking about DSH, be clear whether you mean the runtime (the harness) or the application built on top of it (the superagent). What most people actually want to borrow is the former.


2. Quick recap: what Google Research Harness² does

For the full details, see Harness² Part 1. Here are the highlights:

  • It defines the "harness" as an editable file tree: c1..c4 are always-loaded components (systemprompt.md, guardrails.md, LongTermMEMORY.md, tool_descriptions/) with a combined budget of 24,000 bytes; c5..c8 are on-demand components (sub_agents/, skills/, scripts/, plugin/).
  • It edits this tree automatically via two-level recursion:
    • Inner loop, Propose → Probe → Compose: read the execution trajectories (trajectory.md) of failed tasks, propose multiple candidate patches, run each once in a sandbox, and compose the ones with positive gains into the next generation $H^{(k)}$.
    • Outer loop, Experience Reflector: distill lessons across rounds and write them into c3: LongTermMEMORY.md.
  • It connects to your agent through a BenchmarkAdapter: run() must answer "with this version of the harness loaded, what did the agent produce for this task, and what happened along the way?" For the business-card assistant, I wrote a Go cmd/harness-runner subprocess CLI that the Python Harness² calls.
  • Zero-leakage barrier: gold answers are hidden from both the agent and the Harvester LLM, forcing it to infer general rules from trajectories.

3. DSH vs. Harness²: a point-by-point comparison

3.1 "Harness" means different things on each side

This is the single most important point of the post:

Harness in DSH Harness in Harness²
Refers to The program that runs the agent: agent loop, tool execution, model calls, sessions, permissions What gets fed to the agent: prompts, guardrails, memory, tool descriptions, skills
Form A Node process (runtime) A folder (c1..c8 files)
Analogy How the buckles and reins of a harness are assembled How long each strap on the harness is adjusted
Who changes it Engineers write profiles / patches / plugins Harness²'s optimizer changes it itself

So the two are not competing alternatives; they are an upper and a lower layer. The file tree Harness² optimizes must eventually be loaded and executed by some runtime, and DSH is exactly such a runtime.

3.2 Full comparison

Aspect DeepSeek Harness (DSH) Google Research Harness²
Origin Open-sourced by DeepSeek; the foundation of dsh-superagent Open-sourced alongside a Google Research paper (arXiv:2610.14224)
Language TypeScript / Node (plus a Python SDK) Python
Role Agent runtime Offline optimizer for the agent's harness
Core abstractions Cordis plugins, Profile, Bundle, Patch c1..c8 components, BenchmarkAdapter, Recursion
Primary output The result of one agent run + session events A better harness file tree
When it runs Online, on every request Offline, over multiple rounds against an eval set
Requires an eval set No Yes (plus rubrics and trajectories)
Model Anthropic Messages-compatible endpoint (DeepSeek by default) The optimized agent can use any model; the Harvester is configured separately
Intrusiveness for existing agents High: the agent must run inside DSH Low: write an adapter and externalize config into files
How you observe the agent Session events such as tool/call, tool/result, turn/end trajectory.md (generated from OpenTelemetry spans in the business-card assistant)
Maturity 0.2.1-rc.5, pre-release; options get renamed Research code; interfaces oriented around the paper's experiments
In this series Agent layer of the LINE research bot's online service Offline self-evolution of the LINE AI business-card assistant

3.3 Where do Harness²'s c1..c8 map to in DSH?

Since DSH also "assembles a bunch of things into an agent", we can try mapping Harness²'s eight components onto it. The table below reflects my understanding from actually using DSH; where there is no counterpart in my usage, I say so:

Harness² component Where it lives in DSH How I used it in the LINE research bot
c1 systemprompt.md The system-prompt plugin; the persona can be passed via DSH_SYSTEM_PROMPT prompts/persona.md as the persona; each of the three stages' instructions goes in the user message
c2 guardrails.md Two places: schema validation of tool arguments (required, enum), and patches that set dangerous tools to disabled: true enum on submit_report's error field rejects invalid values; bash and editor are disabled
c3 LongTermMEMORY.md A DSH session is an event stream for a single run, not cross-round memory Not used; cross-stage data lives in Firestore
c4 tool_descriptions/ The description and parameter schema in defineTool(), which the model sees directly Descriptions for web_research and submit_*
c5 sub_agents/ DSH has a built-in subagent tool (visible in the full sdk profile) Not used; also disabled in sdk-minimal
c6 skills/ I did not investigate an equivalent mechanism this time Not used
c7 scripts/ Equivalent to letting the agent run a shell (persistent-bash and similar tools) Deliberately disabled
c8 plugin/ This is the core of DSH itself: Cordis plugins dsh/plugin/index.js registers the research tools

The most interesting finding from this mapping: Harness²'s c8 is the star in DSH, while c1..c3, which Harness² cares about most, get only basic attachment points in DSH. This mirrors their respective roles: DSH cares whether the execution side can be assembled, while Harness² cares whether the content side can evolve.

3.4 Common ground: both move the agent's "equipment" out of the code

Despite operating at different layers, the two share several design instincts:

  1. Externalize configuration into files. The first step in bringing Harness² to the business-card assistant was extracting the prompts hard-coded in .go files into harness/base/; DSH externalizes "which plugins to load and which tools to disable" into profiles + YAML patches. Neither wants you to recompile just to change agent behavior.
  2. Isolate via subprocesses. In the business-card assistant, Harness² calls a Go harness-runner subprocess; DSH itself is a subprocess spawned by the SDK. Either way, the host can be written in any language.
  3. Both need visibility into the agent's process, not just its result. Harness² relies on trajectory.md for diagnosis; on DSH, I rely on session events to extract structured output and to verify that patches took effect. You can only optimize or debug what you can observe.

3.5 Differences: one governs how it runs, the other what it runs

  • DSH's challenges are engineering problems: plugin path resolution, renamed SDK options, a model layer limited to the Messages protocol. These are all about "getting it to run"; I cover ten pitfalls in the next post.
  • Harness²'s challenges are data problems: a good enough eval set, rubrics, zero-leakage design, and high-resolution trajectories. These are all about "making it better".
  • DSH runs on every request, so latency and cost matter; Harness² runs offline, so it can spend more tokens to produce a better file tree, at zero cost once deployed.

4. Can they be combined?

Yes, and conceptually it is quite natural. Taking the LINE research bot as an example, if I wanted it to self-evolve like the business-card assistant, it would look roughly like this:

Combining Harness² with DSH via an adapter

  1. Modeled on the business-card assistant's cmd/harness-runner, write a TypeScript runner CLI that accepts --harness-dir and --task-json.
  2. The runner converts c1 into DSH_SYSTEM_PROMPT, writes c4 into the tool descriptions, and turns part of c2 into a patch (e.g. which tools to disable).
  3. After the run, it renders session events such as tool/call / tool/result into trajectory.md and returns it, together with the report, to the Python-side adapter.

I have not implemented this yet; it simply seems feasible after putting the experience from both projects together. DSH's session events are already closer to "agent decisions" than OpenTelemetry spans, so they should work well as trajectories.


5. When to use which?

Your situation Recommendation
You want an agent runtime that is composable, lets you disable dangerous tools, and lets you swap model endpoints DSH (note: it is pre-release, and the model layer only speaks Messages)
Your agent is already in production and you want prompts, skills, and memory to evolve automatically based on evaluation results Harness² (requires an eval set and execution trajectories)
You already run well on ADK and just want to improve quality Start with Harness²; no need to switch frameworks
You want both Use DSH as the runtime and Harness² as the offline optimizer, connected via an adapter + subprocess

Summary

  1. Despite the shared name, DSH is a runtime, while Harness² is the content a runtime loads plus an optimizer for it. Once this is clear, there is no point asking "which one is better".
  2. DSH's design centers on composability: Cordis plugins + profile layering mean disabling, swapping, or inserting any component takes just a few lines of YAML. The trade-off is that the agent runs in a separate process and must be driven over JSON-RPC.
  3. Harness²'s design centers on evolvability: it splits the agent's equipment into budget-constrained c1..c8 components and uses trajectory-driven, two-level recursion to improve them.
  4. Both tackle different facets of the same goal: freeing agent behavior from code. One frees how it runs; the other frees what it runs.

The next post gets hands-on: Migrating a LINE Research Bot from Go ADK to DeepSeek Harness: Migration Mapping and Pitfalls.

Further reading

Top comments (0)