Back to home

Yuki-takuya-kun

dsh-engine-switch

Route DeepSeek Harness top-level sessions to pluggable loop engines by agent-preset — Claude Code ships as a built-in engine.

Stars
1
Language
JavaScript
Created
Aug 14, 2026
Updated
Aug 14, 2026

Introduction

dsh-engine-switch

English | 中文

A pure engine-switching runtime: routes DeepSeek Harness (DSH) top-level sessions to pluggable engines by agent-preset.

🚧 Pre-release — not yet usable. Routing/swap paths are not end-to-end validated. Do not use in production.

What it is

A standard + runtime that lets presets connect to engines while keeping engines and sessions transparent to each other:

  • Engine = a driver implementing the DSH Agent interface (same interface as the native ReactLoop), registered by a downstream plugin.
  • This plugin ships no engine and no preset. It defines the integration contract and provides three things: preset → engine routing, swap while the session is blank, and preset installation.

Transparency:

  • Engine is preset-unawaremakeAgent receives session/options/engineConfig, never a preset.
  • Session is switch-unaware — the session drives a single Agent; switching engines only swaps the agent driving it (while blank).

Install

dsh plugin --profile web add github:Yuki-takuya-kun/dsh-engine-switch
# then install at least one downstream engine plugin, e.g.:
dsh plugin --profile web add github:<your-account>/dsh-engine-claude-code

Enable

Edit ~/.dsh/profiles/web/cordis.patch.yml:

- id: dsh-engine-switch
  config:
    enabled: true
    # optional: point a preset at an engine
    # engineByPreset:
    #   research: claude-code

Restart the web app. Presets registered by downstream engines appear in the picker; selecting one routes to that engine, anything else → DeepSeek.

Registering a downstream engine

A downstream plugin injects engineSwitch:

export const inject = ["engineSwitch"];
export function apply(ctx) {
  ctx.engineSwitch.register({
    id: "claude-code",              // engine id = preset directory name
    name: "Claude Code",
    description: "…",
    presetDir: fileURLToPath(new URL("./presets/claude-code/", import.meta.url)),
    makeAgent(loopCtx, id, options, session, engineConfig) {
      return new ClaudeCodeAgent(loopCtx, id, options, session, engineConfig);
    },
  });
}

presetDir holds agent.cordis.yml + preset.yml; the framework installs it to ~/.dsh/.agent-presets/<id>/. See Engine API for the full contract.

How it works

  • Replaces the agent factory and routes by preset: engineByPreset[preset] → "preset id = engine id" → defaultEngine.
  • Switching preset while blank (either direction) disposes the old agent and rebuilds a fresh session + the target engine's agent. DSH only allows switching before input, so the framework needs no extra lock.
  • Subagents always delegate to DeepSeek; resume infers the engine from the session log's current preset (resolveSessionPreset).

Config

KeyDefaultMeaning
enabledfalsemaster switch: false = plugin does nothing
defaultEngine"deepseek"engine for unlisted presets (and preset-less sessions); deepseek = delegate sentinel
engineByPreset{}preset id → engine id overrides
engines{}engine id → engine-private config (forwarded verbatim)

Known limitations

  • Pre-release: routing/swap not end-to-end validated.
  • Swap is blank-only (DSH locks the preset once a session has input).

License

MIT. See THIRD_PARTY_NOTICES.md.