dsh-context-offload
Context offloading for DeepSeek Harness (dsh).
A coding agent re-sends its whole history on every step, and most of that history is
tool output it already used: the file it read, the command it ran, the diff it
applied. This plugin releases that content from the model-visible history once
it is no longer needed, replacing each consumed tool call and its results with a
one-line stub. Every original stays in the session log, so nothing is lost —
only the model's view shrinks.
Install
dsh plugin --profile web add dsh-context-offload
Restart dsh web. The plugin mounts into the profile composition and covers every
agent in that profile.
To switch it off without uninstalling, add to the profile's own cordis.patch.yml:
- id: context-offload
disabled: true
What the model sees
A tool unit — the assistant message that issued the calls plus every result
answering them — is shadowed by a single user/message stub:
[tool context offloaded — 2 tool call(s) removed from model context; 39,045 characters released]
- bash(command=cd /Users/me/proj && ls -la && for d in */; do echo …)
- read(path=src/harness/loop.ts)
The original arguments and results remain in the session log. Re-read a file or re-run a command if you need the content again.
Two paths produce that stub:
- Between steps — a policy on
agent/pre-step releases complete tool units
once more than retainUnits newer ones exist, and the accumulated backlog
reaches flushChars. It flushes at most once per flushEverySteps, because
every replacement moves the first divergence point of the request prefix and
flushing on every step would defeat the provider's KV cache on every step.
- On request — the
offload_context tool lets the model unload calls it has
finished with. The request is recorded during the tool call and applied at the
next step boundary, which is the sanctioned surface-mutation point; a tool body
runs mid-step and must not rewrite the surface.
Units whose calls are not all answered — an in-flight or interrupted step — are
never touched, and the system prompt at surface node 0 is never inside a range.
Configuration
All fields are optional.
| Field | Default | Meaning |
|---|
enabled | true | Set false to keep only the model-facing tool. |
retainUnits | 8 | Most recent complete tool units kept verbatim. Counted in units, not steps — step restarts at 1 for every turn, so a step delta across a turn boundary is meaningless. |
minUnitChars | 4000 | A unit smaller than this many text characters is not worth a replacement. |
flushChars | 20000 | Do not break the request prefix for less than this much releasable backlog. |
flushEverySteps | 10 | At most one automatic flush per this many steps. |
maxUnitsPerFlush | 40 | Upper bound on replacements appended in a single flush. |
Where it sits in the composition
This package ships a host-plane bundle: dsh.bundle.patch mounts one row into
the profile composition, which is the only channel a published package has. A
preset-plane mount is possible but must be made by hand — an installed package
cannot contribute an agent-preset root (package.json.dsh carries no preset
field, and a patch cannot compute a path relative to its own package). To scope
this to one preset instead of the whole profile, do not enable the bundle row:
install the package so node_modules can resolve it, and add the row to your own
preset copy:
- id: context-offload
name: dsh-context-offload
Enable exactly one of the two, never both.
compaction-basic remains authoritative for context pressure; this plugin is a
complement. Both append logged surface replacements and both listen on
agent/pre-step, and ordering between them does not matter because each only ever
shadows complete tool units or its own balanced range.
Why you cannot see it in the transcript
Surface replacements are model-only. The human transcript is rendered from
append-origin events on purpose, so a landed replacement never erases conversation
you already read. To observe the effect, watch the context-occupancy ring beside
the composer: it stops climbing and enters a sawtooth, and its click-open panel
shows the conversation segment flattening.
License
MIT