DSH Python SDK config: profile patches and editor patch
DeepSeek Harness Python SDK configuration is not one file; it is four layers: the profile, the profile’s persistent patch, the home patch, and the patches tuple passed to DeepSeekHarness. The tuple is the usual reason a change “disappears next time”—it was never persistent. This article separates the layers, then shows how to add str_replace_editor back.
DeepSeek Harness: What each layer controls
The final tree applies the profile, profile patch, home patch, and per-run patches in order; later layers win. Map them:(source)
| Layer | Location | Scope |
|---|---|---|
| profile | $DSH_HOME/profiles/sdk-minimal/ | base combination and server entry |
| profile patch | profiles/sdk-minimal/cordis.patch.yml | this profile, survives restarts |
| home patch | $DSH_HOME/cordis.patch.yml | every profile in the home |
| constructor patches | DeepSeekHarness(patches=(...)) | this process only |
One rule matters more than the rest: a patch replaces the entire config of the target row, not individual keys. When editing one field, copy the full row first or the other fields disappear.
from pathlib import Path
from deepseek_harness import DeepSeekHarness
workspace = Path("/srv/work/demo").resolve()
dsh_home = Path("/srv/dsh-home/demo").resolve()
with DeepSeekHarness(
provider="deepseek-official",
model="deepseek-v4-flash",
max_tokens=49_152,
cwd=str(workspace),
dsh_home=str(dsh_home),
profile="sdk-minimal",
patches=("/srv/dsh-home/demo/patches/editor.patch.yml",),
) as harness:
result = harness.run("Inspect the repository.", session_id="demo-001")
DeepSeek Harness: Persist a change
To keep a change across restarts, write it into $DSH_HOME/profiles/sdk-minimal/cordis.patch.yml. Steps:(source)
- Initialize the profile —
dsh --profile sdk-minimal --dump-default-config >/dev/null. Expected: the profile directory and default combination exist. - Edit cordis.patch.yml — write only the rows you need; do not paste the whole tree. Expected: the file parses as YAML.
- Dump the effective tree —
dsh --profile sdk-minimal --dump-config. Expected: your change appears with its source file. - Run the SDK again — construct
DeepSeekHarness. Expected: the new setting applies without the constructor tuple.
If step 3 does not show the change, check DSH_HOME first. The SDK only reads the home you pass; it does not silently read ~/.dsh.
DeepSeek Harness: Apply a one-off patch
Use the patches tuple for changes that should not outlive the process. Three good uses:(source)
- Temporary timeout bump — a longer budget for one job. Expected: the setting disappears when the process exits.
- Temporary tool mount — enable
str_replace_editorfor one debugging run. Expected: other jobs do not see it. - A/B comparison — run the same home with two patch files. Expected: results are comparable and neither pollutes the other.
Use absolute paths; order is stacking order. A later patch overrides the same target row from an earlier patch.
DeepSeek Harness: Add str_replace_editor
sdk-minimal does not mount str_replace_editor by default; add it with an editor.patch.yml. The official insert:(source)
- insert:
- id: tool-str-replace-editor
name: '@deepseek-ai/dsh-tool-str-replace-editor'
Three ways to use it:
- Per run — save as
/srv/dsh-home/demo/patches/editor.patch.ymland passpatches=("/srv/dsh-home/demo/patches/editor.patch.yml",). Expected: the next run exposesstr_replace_editor. - Persistent — merge the same insert into
profiles/sdk-minimal/cordis.patch.yml. Expected: every startup includes the tool. - Standard sdk profile — the same patch applies to
sdk. Expected: switchingprofile="sdk"still exposes the tool.
The local filesystem backend resolves relative paths against the runtime working directory and does not confine access to it. Enable the editor only with a sandbox or a disposable checkout.
DeepSeek Harness: Patch replaces the whole config
The official rule is “replace the target row’s entire config”, not deep merge. If the original row has apiKeyEnv, api, and baseURL, a patch that writes only api removes the other two. Copy the full row, change one field, then verify with --dump-config. (source)
DeepSeek Harness: Which configuration path to choose
Persistent profile patch, home patch, and constructor patches solve different problems. Compare:(source)
- Profile persistent patch — for “this SDK app should always behave this way”. Cost: switching homes loses it.
- Home patch — for “every SDK profile on this machine should inherit this”. Cost: broad blast radius during debugging.
- Constructor patches — for “this one run only”. Cost: easy to forget, which silently restores defaults.
A practical rule: validate in the constructor tuple, then move the stable change into the profile patch. That keeps experiments out of long-lived environments.
DeepSeek Harness FAQ
Does editing cordis.patch.yml hot-reload the SDK?
No. Construct DeepSeekHarness again. Persistent patches are read at startup, and a running harness does not watch the file.
Why did my other fields disappear when I changed one field?
Because the patch replaced the entire config. Copy the original row first, then change one field.
Can profile point at a directory I created?
Yes, but it must include @deepseek-ai/dsh-sdk-app or another JSON-RPC server entry. A missing server entry fails startup and does not fall back.
The short version: decide how long the change should live before choosing a layer. One run goes in patches; a lasting change goes in cordis.patch.yml.
FAQ
DeepSeek Harness: four layers: the profile, the profile’s persistent patch, the home patch, and the patches tuple passed to DeepSeekHarness. The profile supplies the base tree, the two patches persist changes, and the tuple applies only to the current process.
DeepSeek Harness: write it into $DSH_HOME/profiles/sdk-minimal/cordis.patch.yml. That is the persistent profile patch. A change passed through the constructor’s patches tuple only affects the current run.
DeepSeek Harness: the default Cordis tree for sdk-minimal does not mount it. Add an editor.patch.yml with an insert for @deepseek-ai/dsh-tool-str-replace-editor, then pass it through patches or merge it into cordis.patch.yml.
DeepSeek Harness requires a profile with @deepseek-ai/dsh-sdk-app or another JSON-RPC server entry. A missing server entry, an unresolved plugin, or an invalid patch fails startup; none of them fall back to another combination.
DeepSeek Harness: yes, but use different session IDs. Use a new session for independent work; reuse the harness, home, and session ID together only when continuing the same persistent conversation.
Related Terms
- sdk-minimal
- sdk-minimal is the minimal profile shipped with the DeepSeek Harness Python SDK. It builds a complete tree on an empty root without dsh-base and contains only the SDK protocol, DeepSeek adapter, local execution, and persistence.— DeepSeek Harness docs - Python SDK
- cordis.patch.yml
- cordis.patch.yml is a persistent profile patch under $DSH_HOME/profiles/<name>/. It uses insert and related operations to modify the existing configuration tree.— DeepSeek Harness docs - Python SDK
- patches tuple
- patches is an ordered tuple of patch file paths passed to DeepSeekHarness. It applies only to the current process and stacks with the profile patch and home patch.— DeepSeek Harness docs - Python SDK
- str_replace_editor
- str_replace_editor is a text-editing tool bundled with the DeepSeek Harness runtime, but sdk-minimal does not mount it by default; you must insert tool-str-replace-editor with a patch.— DeepSeek Harness docs - Python SDK
Sources
- DeepSeek Harness docs - Python SDK· deepseek-ai
- DeepSeek Harness reference - dsh CLI behavior· deepseek-ai