dshkit

Patching plugin config in DeepSeek Harness: the config catalog explained

How to change a plugin's settings in dsh — find the row identifier in the config catalog, target it from cordis.patch.yml, and verify the composed result. With real package IDs and patch YAML.

Updated 2026-08-133 min
Short answer

Every configurable plugin is identified by its package name, and a patch targets that identifier to replace its whole config or insert new rows. Write the patch in $DSH_HOME/profiles/<name>/cordis.patch.yml, then confirm with dsh --profile <name> --dump-config, which prints the composed result after all four layers.

Every capability in DeepSeek Harness is a plugin, and every configurable plugin is identified by its package name. That single fact is what makes the configuration system learnable: you are never looking for a setting, you are looking for a row.

The config catalog

The repository ships a catalog of every configurable plugin, organised by package ID. Each entry carries four things:

  • Identifier — the package name, e.g. @deepseek-ai/dsh-agent-loop
  • Purpose — what the plugin configures
  • Service dependencies — listed as Requires:, e.g. agents, sessions, llm
  • Configuration shape — a TypeScript interface showing every accepted field

That last item is the reason to read the catalog rather than guess: the interface is the complete list of what a row will accept.

A few entries worth knowing:

PackageConfigures
@deepseek-ai/dsh-agent-loopmaxParallelToolCalls, plus an agents array of agent startup definitions
@deepseek-ai/dsh-llm-deepseekThe DeepSeek provider: API-key environment variable, endpoint, thinking-mode policy, token limits, retry behaviour
@deepseek-ai/dsh-session-persistence-jsonlJSONL session log storage: root directory, compression (zstd or none), chunk packing, cache sizing

Writing a patch

A patch is YAML keyed by the row identifier:

# Configure agent-loop concurrency
@deepseek-ai/dsh-agent-loop:
  maxParallelToolCalls: 4
  agents:
    - id: primary-agent
      sessionId: session-123
      cwd: /workspace

Put it in the profile's own file:

$DSH_HOME/profiles/web/cordis.patch.yml

A patch targets a row by identifier and either replaces its whole config or inserts new rows. Treat a targeted row as replaced rather than merged — write the complete config you want for it, not just the field you are changing.

The layer order decides who wins

Patches apply to an empty entry list in this order:

  1. each bundle the profile stacks, in sequence
  2. the profile's cordis.patch.yml
  3. the home-level $DSH_HOME/cordis.patch.yml
  4. any --patch overlay at runtime

Later layers win. So the home-level file beats your profile file — which is the correct behaviour for something meant to apply everywhere, and the most common reason a profile-level edit appears to do nothing.

Two settings worth thinking about before you change them

maxParallelToolCalls bounds how many tool calls run at once. Raising it makes broad mechanical work faster and makes the agent's behaviour harder to follow, because interleaved output loses its narrative order. Raise it for sweeps; leave it low while you are still learning what the agent does.

Session persistence compression. The default zstd is the right choice for anything long-running. Switch to none only when you actively want to read raw session logs with ordinary text tools — and remember that an append-only log of everything the model saw grows faster than intuition suggests.

Verify, always

dsh --profile web --dump-config

Prints the composed result. Compare it with the clean baseline:

dsh --profile web --dump-default-config > /tmp/base.txt
dsh --profile web --dump-config        > /tmp/mine.txt
diff /tmp/base.txt /tmp/mine.txt

The diff is exactly the set of changes your layers make. If what you intended is not in it, the patch did not apply. If it is in it but wrong, a later layer rewrote it.

Keep the patch file in version control

A profile's cordis.patch.yml is the entire description of how your agent differs from stock. It is small, it is text, and it is the thing you will want to explain to a colleague or roll back after a bad experiment.

$DSH_HOME/profiles/web/cordis.patch.yml   → commit this
$DSH_HOME/.credentials.yaml               → never commit this

Frequently asked

How do I find out what a plugin accepts?

The repository ships a config catalog listing every configurable plugin by package ID, with its purpose, its service dependencies, and a TypeScript interface showing every accepted field.

Does a patch merge or replace?

A patch targets a row by identifier and either replaces its whole config or inserts new rows. Treat it as a replacement of the targeted row, and write the complete config you want for it.

Which file should I put a patch in?

The profile's own cordis.patch.yml for anything profile-specific. The home-level file applies to every profile and overrides the profile's own, so use it only for things you genuinely want everywhere.

Keep reading