Module 6 — Harness Teardowns

Teardown: DeepSeek Harness

Reading time ~20 min · Last reviewed Sep 2026 · Quiz at the end

For most of the short history of agents, the division of labour was clean. Labs shipped models. Somebody else, usually a product team or an open-source community, built the harness that turned the model into an agent. Where labs did ship harnesses, they were products first: a CLI, an IDE extension, a hosted agent. On 13 August 2026, the day DeepSeek-V4-Pro reached general availability, DeepSeek published something different: an MIT-licensed agent harness whose documentation reads less like a product manual and more like an architecture argument. It is called DeepSeek Harness, dsh for short, and it is the most complete public statement any frontier lab has made about how it thinks a harness should be built.

This lesson reads that statement closely. We go through the primary documents in the repository (the README, the safety notice, the architecture and lifecycle docs, the package map, the wire-extension reference, and the READMEs for compaction, guard, sandbox and spill) and the DeepSeek-V4 release material, and we ask two questions throughout. What design decisions did they make, and which of those should you copy into your own harness? The mechanisms here map almost one-to-one onto earlier lessons in this course, which makes dsh a good revision exercise as well as a teardown. Lesson 24 does the same for Claude Code, Codex and the open harnesses.

Pitfall

dsh moves fast. Everything below was checked against the repository's master branch in late September 2026. The README says plainly that the project is in developer preview and that there will be compatibility-breaking changes. Treat specific names (event types, package ids, config keys) as a snapshot. The design ideas are the durable part.

1. What dsh is and why it matters

The repository at github.com/deepseek-ai/deepseek-harness (2026) was created on 13 August 2026 under the MIT license, with the one-line description "Everything is a Plugin." It runs locally with npx @deepseek-ai/dsh web, which starts a web UI on 127.0.0.1:3080. The same runtime ships as several profiles (web, headless, sdk, sdk-minimal, acp), an Electron desktop app, and Python and TypeScript SDKs. A week later DeepSeek's V4-Flash-Vision-Exp announcement (2026) noted that dsh 0.1.1 shipped the same day with out-of-the-box support for the new multimodal model. The harness is built on Cordis, a plugin framework whose design the README points to in an arXiv paper titled A Programming Paradigm for Spatiotemporal Composability (2026).

Why does this matter if you never run it? First, it is a lab telling you, in running code rather than a blog post, where it thinks the leverage is: the loop, the log, the cache, compaction. Second, it documents its invariants, not just its behaviour; rules such as "Model-visible means logged" come with the runtime check that enforces them, which makes the harness teachable. Third, it is not positioned as the only way to use the model: DeepSeek's V4 releases advertise integration with other harnesses (section 8). dsh is a reference and a statement of intent, not a walled garden, and that matters when we get to benchmarks.

Key idea

When a lab ships its own harness alongside its model, read the harness as part of the model release. The weights tell you what the model can do; the harness tells you what the lab thinks the model needs around it to do it reliably.

2. Architecture: no privileged core

Everything is a plugin, including the loop

The central claim in docs/architecture.md (2026) is that every part of the product is a plugin: the model adapter, the tool registry, the session log, and the agent loop itself. The doc's phrasing is direct: there is "no privileged core to patch." The core packages exist (core/session, core/system-prompt, core/tools, core/agent, core/agent-loop, llm/llm), but each one contributes a service to a shared context (ctx.sessions, ctx.tools, ctx.agentLoop, ctx.llm), and each can be replaced from configuration. The package map in packages/README.md (2026) adds the rule that makes this work in practice: extension plugins depend on service definitions, never on concrete providers. Tool and UI plugins talk to dsh-agent, the interface, not dsh-agent-loop, the default implementation.

If you've read lesson 2, you'll recognise the layers; what's new is the refusal to rank them. Most harnesses have a hard-coded loop with extension points bolted on. dsh inverts that: the loop is just the plugin that currently holds the ctx.agentLoop slot.

Registrations are reversible effects

In Cordis, a plugin's registrations (services, event listeners, tools, commands) are effects that unwind when the plugin unloads. This sounds like an implementation detail. It is actually what makes hot reload safe, and it is what makes a runtime-modifiable harness possible at all. dsh ships an extensions group for agent runtime self-modification (live plugin inspection and model-written mount and unmount). You can only let a model mount code into a running harness if unmounting is guaranteed to leave no residue. The same property underlies the self-improving harnesses of lesson 22: a candidate change you cannot cleanly revert is a candidate you cannot safely evaluate.

Layered YAML composition

A running dsh is a plugin tree composed at boot from ordered layers. A bundle is a distributable set of config rows and the code they mount; a profile is a named stack of bundles plus the user's own patch file. The architecture doc gives the order: each bundle in the profile's order, then the profile's cordis.patch.yml, then the home-level one, then any --patch overlay. A patch addresses a row by id and replaces its whole config, or inserts new rows. dsh --profile web --dump-config prints the tree your machine will boot. Here is a short excerpt from the shared base bundle, showing both the row format and how DeepSeek documents a decision inline:

# From packages/bundle/base/cordis.patch.yml (deepseek-harness, master, Sep 2026), abridged
    # Fresh-agent Ralph iteration over a build-time-fixed script. Off by
    # default: the tool description restricts `ralph` to runs the human
    # explicitly asked for, and completion is a worker self-report, not an
    # independent evaluation.
    - id: tool-ralph
      name: '@deepseek-ai/dsh-tool-ralph'
      disabled: true
      config:
        subagentProvider: spawn
        maxRounds: 64

Two things are worth noticing. The config is the documentation: the reason ralph is off lives next to the switch. And the reason given is an evaluation argument. A loop whose completion signal is the worker's own report is exactly the self-grading problem lesson 20 warns about, and DeepSeek chose to ship it disabled rather than pretend otherwise.

Capability seams and execution worlds

dsh names the unit of swappability a seam, with three roles: a Service Definition declaring the interface, a Service Provider implementing it, and a Consumer using it, often a model-facing tool. The architecture doc is strict: one role alone is not a seam, and adding a capability means designing all three. Look at the package groups and you see the pattern everywhere. compaction/ is a definition, a basic provider, and a /compact command consumer. ptc-runtime/ is a definition, a sandboxed Node provider, and the "PTC mode" consumer. spill/ is a storage seam, a local backend, and a tool-result policy.

The payoff is the execution world. Filesystem and subprocess providers share one world, so pointing them at a remote sandbox (the ssh/ group ships paired filesystem, subprocess and sandbox providers) moves Bash, the persistent PTY, and LSP with them, with no provider forks. This is the property lesson 12 argued for in the abstract: where tools execute should be one decision, made once, not a setting you must remember to flip in every tool. Subagents work the same way. The subagent family offers a fresh in-process child, a history-seeded child, or an out-of-process child backed by ACP, Codex, Claude Code or another harness runtime, all behind one interface. A DeepSeek harness that can delegate a turn to a competitor's harness is a strong signal that the seams are real.

Key idea

Design capabilities as definition + provider + consumer, and group providers that must move together into a single "world". The test of a seam is whether swapping one provider changes the product coherently. If moving the filesystem to a VM leaves your shell tool running locally, you don't have a seam, you have a bug waiting for a user.

3. The loop as an explicit state machine

Lesson 4 described the agent loop as a few lines of pseudocode. dsh's loop is that pseudocode with every edge named. The vocabulary is precise: a step is one model request plus the tools it calls; a turn is zero or more steps, opening before its first input is claimed and closing once nothing is owed. The lifecycle sequence (2026) and the architecture doc's turn-flow listing give the order, which compresses to:

turn/start
  claim pending input from the inbox
  assemble system prompt sections + tool schemas
  agent/pre-step        (waterfall)  -> reject | enter(messages, startsRequestSeries?)
  step/start
  agent/request         (waterfall)  -> prepare the call, resolve the route
  log system/message, user/message, request/header|context
  derive and FREEZE the request from the log
  llm/stream            (waterfall)  -> assistant/message  or  assistant/attempt
  agent/request-error   (waterfall, on failure) -> retry action or original error
  for each tool call (classified by executionMode):
    tools/pre-execute -> tools/execute -> tools/post-execute   (waterfalls)
    tool/call ... tool/result  (results committed in model order)
  step/end
  if tools owe another request, or new input arrived: next step
  agent/turn-stopping   (serial checkpoint, can keep the turn alive)
turn/end

(Condensed from docs/architecture.md; event names as documented, ordering simplified.)

Several details repay attention. The hook points are waterfalls: each listener must call next() to delegate, so a plugin wraps the downstream behaviour rather than merely observing it. agent/turn-stopping is the exception: it is serial, has no next(), and is where a plugin can object to the turn ending. That is the natural home for a goal-continuation policy or a "did you actually run the tests?" check, the stop-condition logic lesson 15 discusses.

Tool execution is not a naive loop either. Pending calls are classified by an executionMode and run through what the lifecycle doc calls "barriers and bounded rolling pool": calls that can overlap run concurrently up to a bound, calls that must be exclusive act as barriers, and results are committed to the log in the order the model emitted them regardless of which finished first. Parallelism is an execution concern; the transcript the model sees stays deterministic.

Finally, cancellation and retry are specified, not improvised. Cancellation during the async preparation phases commits neither the system prompt nor the user messages. A retry after a request error reuses the same rendered assembly without re-running pre-step or re-admitting users. Anyone who has debugged a harness that duplicated a user message after a 529, or lost one after a cancel, knows why this is spelled out.

4. "Model-visible means logged"

If you take one idea from dsh, take this one. The session log is an append-only list of events, and it is the single source of the context the model sees. The architecture doc states the rule in three words, "Model-visible means logged", and backs it with a runtime invariant that checks every model request can be reconstructed from the log. Model history is not a mutable array of messages held by the loop; it is a projection computed from the log by deriveMessages(). Fork, resume, transcripts, telemetry and persistence are all derived from the same durable events.

The consequences are sharp:

This is the same move that Anthropic's Managed Agents write-up (2026) describes from a different direction: keep the session log outside the context window and treat the harness as stateless over it. dsh adds the enforcement. A projection seam (ctx.sessionProjections) lets registered units fold events incrementally into typed state, so UIs and plugins read derived state instead of keeping their own shadow copies.

// Illustrative example (TypeScript): the invariant, reduced to its core.
// Not dsh code; a sketch of the pattern for your own harness.
type Event = { seq: number; type: string; data: unknown };

function deriveRequest(log: Event[], projections: Projection[]): ModelRequest {
  let msgs = baseProjection(log);              // system/user/assistant/tool events -> messages
  for (const p of projections) msgs = p(msgs, log); // pure: same log in, same view out
  return freeze({ messages: msgs });
}

async function sendStep(log: Event[], projections: Projection[], llm: LLM) {
  const req = deriveRequest(log, projections);
  // The check: rebuilding from the durable log must give the identical request.
  assertDeepEqual(req, deriveRequest(reloadFromDisk(log), projections));
  return llm.stream(req);
}

The payoff: "what exactly did the model see on step 14?" becomes a replay rather than an archaeology project, evaluation becomes replayable (lesson 17, lesson 18), and forking is cheap: dsh forks a session at a turn boundary by seeding a new agent with a prefix of the parent log.

Key idea

The context window should be a pure function of an append-only log plus registered projections. Anything the model sees that you cannot reproduce from the log is a debugging dead end and an evaluation leak. Enforce it with a check, not a convention.

5. Cache-aware prompt management and wire extensions

With a large context window, the dominant cost of a long agent session is re-reading the prefix on every step, which is why prefix-cache hit rate matters so much (see lesson 26). dsh treats cache stability as an architectural concern rather than a tuning knob, in three ways that the architecture doc describes.

The system prompt is a logged surface node. The prompt travels only as system/message history. When it changes, a capable route appends the non-empty update after the cached history instead of rewriting the head of the conversation; supported tool updates are handled the same way. Rewriting the prefix, which would invalidate the cache, only happens on routes that can't handle appended updates or at the start of a new request series.

A new request series is a deliberate act. A plugin's agent/pre-step decision can set startsRequestSeries, and the loop then logs a fresh request/header. Surface replacements (compaction) and image-offload decisions start a new series; an unchanged resume continues the old one. Cache invalidation becomes something you declare and can find in the log, not something that happens because a timestamp crept into the system prompt.

Harness metadata stays out of the model-visible prefix. The wire-extension reference (2026) defines extra HTTP headers and top-level JSON fields (prefixed dsh_) that the DeepSeek adapter adds to requests. They sit outside messages, system prompts and tool schemas, "so they do not add model-input tokens or alter the model-visible prefix." Each extension has its own version number, a registry reserves one provider per field name, collisions fail before dispatch, and if the merged body fails to serialise the adapter sends the base request without extensions. It's a clean pattern for any harness that needs to send routing or telemetry metadata alongside a request without paying for it in cache misses.

The Manus context-engineering post (2025) made the case for stable prefixes and append-only context as practitioner advice. dsh encodes the same advice as loop semantics. The MCP 2026-07-28 specification (2026) moved in the same direction by recommending deterministic tools/list ordering for prompt cache hit rates; lesson 11 covers that.

6. Layered compaction and spill

Lesson 6 argued that compaction should be a policy with ordered, cheapest-first stages, not a single "summarise everything" button. dsh's compaction family is a textbook instance. According to the compaction group README (2026) and the lifecycle doc:

Spill is the complementary mechanism. The spill group README (2026) describes storing full text outside the model's context and returning a locator plus retrieval guidance. Tool-result spilling is opt-in through maxInlineTokens, and the shipped base bundle turns it on at 12,500 tokens. On storage failure it keeps the original result. Spill handles the single huge output at the moment it arrives; compaction handles the accumulated history later. And because compaction is a projection registered against the log, the pre-compaction history is still in the log for replay and audit.

# Illustrative example: the dsh-style compaction order as a policy.
on pre_step(tokens):
    if tokens < soft_limit: proceed
    run stage_1  prune_oversized_tool_results()   # cheap, lossy only on bulk output
    if still over: stage_2  summarize_oldest(keep_recent=N)  # one extra model call
    mark startsRequestSeries                      # cache reset is declared, not accidental

on request_error(err):
    if err is context_overflow and (stage_1 or stage_2 made progress): retry once
    else: surface original error                  # never loop on a no-op compaction

7. The capability inventory

dsh's package map lists more than fifty groups. Most are plumbing; the ones below are model-facing capabilities or policies that change agent behaviour. Descriptions are condensed from each group's README; the right-hand column tells you where this course covers the underlying concept.

Capability (package group)What it does in dshCourse lesson
ptc-runtimeProgrammatic tool calling ("code mode"): the model writes one program that calls host functions as async calls, run in a fresh sandboxed Node process (Python backend experimental); only printed output and the return value come back.11, 12
workflow (incl. ralph)Model-written orchestration scripts that fan out subagents on the PTC runtime; ralph runs a fixed sequence of fresh agents and ships disabled.16, 15
goalOne durable completion objective per session that survives restarts, resumes and forks; /goal for humans; automatic continuation is a separate opt-in package.15
scheduleOne-shot, recurring or cron reminders that arrive as ordinary follow-up messages in the original conversation and survive host restarts.15
jobsBackground work registered as jobs the owning agent can read, wait on or cancel without blocking its turn; completion is pushed to the owner, not polled.4, 15
planPlan mode: explore and design, then present a plan for approval. It guides rather than restricts; every tool stays available and safety limits are configured separately.9
todoThe model-facing todo_write tool for working-state recitation.5, 8
skillDiscoverable instruction packs loaded on demand via a skill tool or /name, from project, user or custom directories.11
mcpExternal MCP servers' tools and resources exposed as native tools, scoped to callers with a configured server.11
acpAn automation-only Agent Client Protocol server; the matching client lets other harnesses spawn dsh, and dsh spawn them.16
hooksRuns existing Claude Code or Codex hooks.json command hooks (supported subset) at session start, prompt, tool and stop events.13
computer-use, browser-useExclusive provider registration for desktop and browser operation; current providers are experimental.11, 14
lspDefinitions, references, implementations and hover through configured language servers; moves with the execution world.11
sandboxProcess confinement with read-only, workspace-write and danger-full-access modes; bwrap then Landlock on Linux, Seatbelt on macOS, restricted tokens on Windows; denied calls can retry through one-time user-approved escalation.12, 14
guardAdvisory repeat-call reminders (base bundle: at 3, 5 and 8 identical calls) and a deadline enforcer for tools that declare a timeout.13
compaction, spillLayered compaction and out-of-context storage (section 6).6
session-queryRetrieval over past sessions: bounded reads, lineage, semantic filtering, SQLite full-text search.8
Agent Teams (experimental)An opt-in coordination seam with a durable roster, task board and mailbox layered over continuable subagents.16

Two entries deserve a second look. The sandbox README is candid about scope: confinement is "same-world only", sharing the host kernel and filesystem, while containers, microVMs and remote executors replace whole capabilities rather than registering as sandbox backends. That is the right mental model from lesson 12: an OS-level sandbox reduces blast radius on your machine; isolation from your machine is a different execution world. And the guard README describes the repeat-call reminder as advisory: it never blocks a legitimate repeated call, and it resets on a new user message. It nudges the model out of a doom loop; it does not pretend to be a safety control.

8. Model–harness co-design with DeepSeek-V4

A harness built by a lab alongside its model invites the question: what did the model change about the harness, and vice versa? Here the sources support some statements and not others, and it is worth being exact.

What the V4 release material says

From the Hugging Face DeepSeek-V4 blog (April 2026):

From DeepSeek's API news: the April V4 preview (2026) says V4 is "seamlessly integrated" with Claude Code, OpenClaw and OpenCode, and supports OpenAI ChatCompletions and Anthropic APIs. The August GA announcement (2026) adds reasoning effort levels (low for simple tasks, high for daily agent workflows, max for complex tasks) and native OpenAI Responses API support, "optimized for Codex". The August 21 vision release lists Chat Completions, Messages and Responses as supported protocols.

How this lines up with dsh

Several dsh decisions fit these model properties closely. The log embeds each assistant message's exact compact stream rather than a lossy rendering, which is what you need when reasoning must be replayed across tool rounds. The cache discipline in section 5 is what makes a 1M-token window economical in practice: a small KV cache lowers the cost of holding long context, and a stable prefix lowers the cost of re-sending it. The loop's step/turn model with background jobs, goals and schedules assumes sessions long enough to need them.

But be careful about the direction of the claim. The primary sources reviewed for this lesson contain no DeepSeek statement that V4 was trained inside dsh, or that DSec rollouts used dsh as their harness. The V4 posts don't mention dsh at all. What the sources do show is that DeepSeek targets several harnesses: Claude Code, OpenClaw, OpenCode, and Codex via the Responses API. dsh is DeepSeek's reference for how to use the model well. It isn't the only harness the model was built to serve, and it would be wrong to present it as the model's native environment.

Key idea

Model features create harness obligations. Retained interleaved thinking obliges you to store and replay reasoning exactly. A cheaper long context rewards cache-stable prompts. A tool-call format built to avoid escaping failures tells you where the model was fragile. When you adopt a new model, read its release notes as a list of harness requirements, not just capabilities (see lesson 3).

9. The benchmark story

The official numbers first. The Hugging Face V4 post reports, for V4-Pro-Max in April: Terminal-Bench 2.0 67.9, SWE-bench Verified 80.6, MCPAtlas Public 73.6, Toolathlon 51.8. The August GA announcement includes a benchmark table as an image; its figures aren't in the page text, so we don't quote them here.

Then the story that circulated after GA, which is secondary and should be read as such. According to FindHarness's write-up (2026), DeepSeek-V4-Pro (0813) was reported at 87.9 on Terminal-Bench 2.1 using DeepSeek's own harness setup, against 54.68 when rerun under the Terminus 2 reference harness, a result the article attributes to Vals AI. FindHarness itself describes its sources as community reports, not an official DeepSeek statement. We could not find the 87.9 figure in DeepSeek's text-based primary material.

Take the gap as a hypothesis, not a finding. It is entirely plausible: a harness tuned by the model's authors, with a tool format, compaction policy and prompt structure matched to the model, should beat a generic reference harness. It is also the kind of number that needs a disclosed harness, disclosed resource limits and repeated runs before it means anything, which is the argument of lesson 19. The lesson for you is not "dsh is worth 33 points". It is that on agentic benchmarks the harness is part of the system under test, and a score without the harness named is half a result.

Pitfall

Don't select a model on an own-harness score and then deploy it in a different harness. If a vendor's best number comes from its own harness, either adopt that harness for the evaluation, or rerun the model in yours. Your production harness is the only one whose score predicts your production behaviour.

10. What to be careful about

It is a developer preview, and it says so

The SAFETY.md notice (2026) is blunt. dsh is experimental developer-preview software that "has not undergone a security audit" and must not be treated as secure or production-ready. It can execute model-generated code, load third-party plugins, and reach the network, processes, credentials and files made available to it. Sandboxing and approval prompts reduce risk but do not guarantee isolation, and even correctly enforced restrictions cannot protect resources the project is allowed to access. The recommended posture: least privilege, a disposable VM or container, backups, no sensitive credentials unless you accept the risk, and review of plugins and commands. The app-boot README adds that plugin version checks "are not a sandbox against malicious package code". Everything from lesson 14 applies, doubly so given the plugin model: a plugin is arbitrary code with full access to the context.

Default-on session-log upload to DeepSeek

This is the item most readers miss, so here is exactly what the documents say. The wire-extension reference and the session-log-deepseek README (2026) describe what the DeepSeek adapter adds to requests sent to the official DeepSeek API (or to any gateway configured as its baseURL):

None of these fields enter the model's input; they are provider metadata. The documents reviewed for this lesson do not state what DeepSeek does with the uploaded logs, and we won't speculate. Separately, the base bundle README describes an OpenTelemetry session upload that defaults to FEEDBACK_ONLY: submitting feedback or a rating releases the session prefix through that path, and DISABLED prevents capture.

How to evaluate and disable, per the docs. Both contributors have an enabled key, and the session-log README says an overlay opts out with enabled: false. In the base bundle they are rows with ids session-log-deepseek and plugin-package-inventory-deepseek. A home-level overlay along these lines should do it; the row ids and keys are from the repository, but verify the result against your version with dsh --dump-config before relying on it:

# $DSH_HOME/cordis.patch.yml  (constructed from documented row ids and keys;
# a patch replaces the row's whole config, so restate any fields you keep)
- id: session-log-deepseek
  config:
    enabled: false
- id: plugin-package-inventory-deepseek
  config:
    enabled: false

Note what this doesn't cover. The documents describe no switch for the anonymous-user-id and session-id headers on official-adapter requests. If your threat model can't accept those, route through a gateway you control or use another provider adapter; the reference says the provider-neutral interface does not implement these additions. And if you run through a third-party gateway via baseURL, that gateway receives the same fields the official endpoint would. For an organisation, the practical checks are: dump the config, confirm the two rows are disabled, and inspect an outbound request body once to see what actually leaves the machine.

11. What to steal

You don't have to adopt dsh to benefit from it. These are the design decisions worth copying into any harness, each tied to the lesson where the concept lives.

  1. Make the context a projection of an append-only log, and check it. "Model-visible means logged", with a runtime assertion that each request is reconstructable. Content-altering plugins register pure projections instead of mutating history. This one rule gives you replay, fork, audit and honest evals. (Lesson 6, lesson 17.)
  2. Log failed attempts separately from history. A failed or retried model call is evidence for debugging but not context for the model. Two event types (assistant/message and assistant/attempt) keep both. (Lesson 4.)
  3. Name your loop's states and give hooks wrap-around semantics. Step versus turn, waterfall hooks that must call next(), and a single serial turn-stopping checkpoint where "are we really done?" policies live. Write down retry and cancellation semantics. (Lesson 4, lesson 15.)
  4. Treat cache invalidation as an explicit, logged decision. Append prompt and tool updates after cached history; start a new request series only on purpose; keep harness metadata out of the model-visible prefix. (Lesson 26, lesson 6.)
  5. Compact in cheapest-first layers and retry only on progress. Spill large outputs at arrival, prune tool results before summarising, summarise the oldest and keep the recent, and never retry a compaction that changed nothing. (Lesson 6.)
  6. Build capabilities as definition, provider and consumer, grouped into execution worlds. Filesystem, shell, PTY and LSP should move together when execution moves to a VM or remote host. (Lesson 12.)
  7. Make every registration reversible and every default visible. Reversible effects make hot reload and runtime extension safe; id-addressed config layers with a dump command make "what am I actually running?" a one-line answer. (Lesson 22, lesson 13.)
  8. Be honest in defaults about what a mechanism can and can't guarantee. dsh ships ralph off because its completion is self-reported, calls its repeat guard advisory, calls its sandbox same-world, and tells you in SAFETY.md not to trust it. Documenting a component's limits is itself a control. (Lesson 20, lesson 14.)
In practice

This week, audit your own harness against the first and fourth items. Pick one real session and try to reconstruct, from persisted data alone, the exact request your harness sent on its fifth model call. List every input you couldn't reconstruct (a timestamp, an injected file listing, a mutated message) and decide for each whether it becomes a logged event or a pure projection. Then grep your prompt assembly for anything volatile above the conversation history, and move it below. If you want to see the reference, run dsh in a disposable VM with the session-log overlay applied, and read its log for one short task alongside the lifecycle doc.

Key takeaways

Check your understanding

1. Your team adds a plugin that redacts customer email addresses from tool results before the model sees them. It works by editing messages in the in-memory history array. Following dsh's design, what is the main problem, and what should you do instead?

Security controls are exactly where reproducibility matters most. Under "Model-visible means logged", nothing is exempt: if you can't reconstruct what the model saw, you can't audit whether the redaction worked.
Moving the mutation later makes it less visible, not more. The request would still differ from anything derivable from the log, breaking replay and the reconstructability check.
Correct. dsh requires plugins that change existing message content to register pure projections, so the model-visible view is a deterministic function of the durable log and detached readers can reproduce it.
Compaction is triggered by token pressure and is lossy in unpredictable ways; relying on it for redaction means the data is visible until pressure builds, and it conflates two unrelated policies.

2. After adding a "current git status" block to the top of your system prompt, your harness's per-task cost roughly doubles on long sessions with no quality change. Which dsh practice most directly addresses this?

Correct. A changing block at the head of the prompt invalidates the prefix cache on every step. dsh appends prompt updates after cached history and treats prefix rewrites as explicit new request series.
More frequent compaction starts more new request series, which resets the cache more often. It would likely make the cost problem worse.
Wire extensions are provider metadata the model never sees. If the model needs git status, it must be in model-visible context; the fix is where it goes, not hiding it.
The guard addresses repeated identical tool calls. The cost problem here comes from prompt structure and cache invalidation, not from the model's behaviour.

3. A vendor reports a much higher agentic benchmark score for its model using its own harness than third parties get with a reference harness. You plan to run the model inside your company's existing harness. What is the soundest conclusion?

A tuned harness legitimately improves results; the gap isn't evidence of inflation. The issue is that the number describes a different system from the one you'll run.
A reference harness is useful for comparing models under equal conditions, but it isn't your harness either. Your prompt structure, tools and compaction can move results in either direction.
Averaging two measurements of two different systems doesn't estimate a third system. It produces a number with no referent.
Correct. On agentic benchmarks the harness is part of the system under test. Only an evaluation in the harness you'll deploy, or a like-for-like comparison, predicts production behaviour.

4. You move your agent's execution from the local machine to a remote VM by swapping the filesystem provider. Tests pass, but the model's shell commands still run on the developer's laptop. In dsh's vocabulary, what went wrong?

Sandbox modes confine processes within one world; the sandbox README says remote executors replace whole capabilities rather than acting as sandbox backends. A mode change wouldn't relocate execution.
Correct. dsh groups filesystem and subprocess providers into a shared execution world so pointing them at a remote sandbox moves Bash, PTY and LSP together. Swapping one provider alone splits the world.
In dsh the loop doesn't decide where tools execute; providers behind the capability seams do. Replacing the loop wouldn't fix a provider mismatch.
The point of a seam is that the consumer (the model-facing tool) stays the same while providers change. The fix is a coherent provider set, not a new interface.