Back to home

euuuuuuzer

dsh-loop-dock

A loop dock for DeepSeek Harness: one harness, multiple agent loops.

Stars
4
Language
JavaScript
Created
Aug 16, 2026
Updated
Aug 16, 2026

Introduction

dsh-loop-dock

One harness. Multiple agent loops.

CI GitHub release License: MIT Node >=22.19

dsh-loop-dock is a community infrastructure plugin for DeepSeek Harness (DSH). It does not design a new agent loop. It provides the dock that lets many loop providers exist in one harness and lets each agent choose which one runs it.

中文说明

Quick Start

  1. Install DeepSeek Harness 0.1.0-rc.6 and pnpm.

  2. Download dsh-loop-dock-0.1.0.tgz from the latest GitHub Release.

  3. Install it into a clean web profile:

    dsh plugin --profile web add ./dsh-loop-dock-0.1.0.tgz
    dsh web
    
  4. Open Settings → General → Default driver and choose fake-driver.

  5. Create a new session and send any message. The reply is local:

    [FAKE-DRIVER] fake driver reply — generated locally, no model call.
    

No API key or network is needed for this first check.

Why dsh-loop-dock?

A model's ceiling is not the model alone. The same model can behave very differently depending on turn structure, tool discipline, context management, planning strategy, and execution workflow.

Community plugins have already shown this: small changes around one loop — a minimal-first preset, a prompt section, a bootstrap hook — can give the same model meaningfully different behavior.

DSH already made the Agent Loop a plugin, but the slot is still effectively single:

Agent A ─┐
Agent B ─┼──> Loop X
Agent C ─┘

dsh-loop-dock opens the next step:

Agent A ──> Loop X
Agent B ──> Loop Y
Agent C ──> Loop Z

One harness. Multiple specialized loops.

What does the dock do?

The dock is intentionally simple. It does not decide how a loop reasons.

It provides:

  • loop registration
  • loop selection
  • agent-loop binding
  • driver delegation

The community builds the loops. The dock makes them composable.

Example

A future DSH setup could look like:

agent-loop-dock:
  agents:
    - id: coder
      provider: deepseek-official
      model: deepseek-v4-pro
      loop: coding-loop

    - id: researcher
      provider: deepseek-official
      model: deepseek-v4-flash
      loop: research-loop

    - id: planner
      provider: provider-c
      model: model-c
      loop: planning-loop

coding-loop, research-loop, and planning-loop are community-registered loops. Each agent gets:

one agent
+ one suitable model
+ one suitable loop

instead of forcing every model and task through the same execution pattern.

Try it without a model key

The bundled patch registers fake-driver next to the real default driver. Switch the Settings row to fake-driver, create a new session, and send any message. It replies locally:

[FAKE-DRIVER] fake driver reply — generated locally, no model call.

No API key and no network are involved. This makes loop and driver routing visible in the first minute.

Architecture

ctx.agents.create / resume
        |
        v
   dsh-loop-dock
   (AgentFactory layer)
        |
        +-- LoopRegistry
              |     |     |
              v     v     v
            Loop A Loop B Loop C
                    |
                    v
              Agent Driver
                    |
                    v
                  Model

The dock separates two concepts:

  • Strategy loop — reuses an existing driver and only installs agent-scoped setup such as prompts, presets, hooks, tools, and policies. This is the common case.
  • Driver loop — a complete custom loop implementation owning createAgent, resume, and turn control flow. This is for fundamentally different execution architectures.

Current Status

Pre-alpha, but runnable.

  • ✅ Loop registry
  • ✅ Agent → loop routing
  • ✅ Durable loop + driver binding
  • ✅ Driver selection
  • ✅ Strategy loop protocol
  • ✅ Driver loop protocol
  • ✅ Default headless driver
  • ✅ Official standard strategy slot
  • ✅ Multi-agent integration tests

The dock is working. The ecosystem is the next step.

See docs/architecture.md for the roadmap.

FAQ

  • preset, loop, and driver — preset defines tools/prompt sections; driver is the engine; loop is the complete loop an agent runs.
  • Official dsh-agent-loop — the dock disables the official row and owns the single AgentFactory slot; a vendored headless derivative is the default driver.
  • fake-driver — a local debug driver that never calls a model or the network; it always replies with [FAKE-DRIVER].
  • Do loop authors need a full driver? — no, strategy loops only implement setup(agentCtx); a driver loop is only for changing turn control flow itself.

Full answers: docs/faq.md.

Terminology

Names follow DeepSeek Harness's own vocabulary (the official package @deepseek-ai/dsh-agent-loop never uses "engine"; it speaks of the "agent factory and driver service"):

Our termWhat it meansCommon / official phrasing
driverThe core agent-loop implementation that owns the createAgent/resume contract and drives turns (HeadlessAgentLoop is the vendored official driver).Official DSH: agent loop / driver ("agent factory and driver service"). Other harnesses often say engine (e.g. Codex engine) — DSH does not use that word.
loopThe COMPLETE loop an agent runs, as registered in the LoopRegistry: a strategy loop (reuses a driver + installs agent-scoped setup) or a driver loop (kind: 'driver', a full custom driver). loop is the whole loop; driver is only its engine part.Community: agent loop / loop. Do not use "loop" for the engine layer.
strategy loopA loop that reuses a driver and only installs per-agent setup (mount a preset, add hooks). This is the common case.Roughly: a preset/profile plus an adapter on top of one engine.
driver loopA loop that IS a complete driver (createAgent/resume), for control flow that differs from the default driver.Roughly: a full engine implementation.
presetDSH's per-session composition (tools + prompt sections), selected via the native picker.Official DSH: preset. Note: in everyday conversation "preset" sometimes means the loop — we always mean the tool/prompt composition.
model routeThe provider/model (+ reasoningEffort) a session's requests use.Community: model config / model selection.
AgentFactoryThe createAgent/resume contract the factory registry delegates to (ctx.agents.setFactory).Official DSH: AgentFactory.
harnessThe whole agent runtime platform (DSH itself, or Codex, etc.).Common term across the ecosystem.
bindingThe durable { loop, driver? } selection the dock records on a session at creation (agent-preset/selected data.agentLoopDock).Recorded selection / route binding.

These concepts relate as follows: preset defines the tools and prompt sections, driver executes turns, loop is the complete loop an agent runs (strategy loop = driver + setup; driver loop = a full custom driver), and model route decides which LLM answers. Sessions pick a preset; the dock derives the loop; the loop (or settings) picks the driver; the request uses the model route.

Implementation status

Pre-alpha but runnable: the routing core, the vendored headless official driver, and the shipped official standard strategy slot are implemented and tested together.

PieceStatus
Named loop registry✅ implemented
Agent → loop routing✅ implemented
Durable loop + driver selection (known event binding, preset fallback)✅ implemented
Local no-model ping adapter (loop-ping)✅ implemented
Effective-preset model-route following (hero-chip switching)✅ implemented
Fake driver for dual-driver testing (fakeDriver: true)✅ implemented
Web Settings "Default driver" row (agentLoops Remote + client.js)✅ implemented
Strategy-loop + driver-loop provider protocol✅ implemented
standard strategy slot✅ registered
Headless default driver (official loop derivative)✅ vendored, see docs/default-driver.md
Two-agent real-driver integration test✅ passing
Core SessionHeader.agentFactory field❌ upstream follow-up only

Track the roadmap in docs/architecture.md; the original motivation and design notes live in DESIGN.md.

Model

ctx.agents.create / resume
        |
   dsh-loop-dock (the only AgentFactory)
        |
        +-- LoopRegistry (the slots)
        |     +-- standard           (strategy: standard preset)
        |     +-- community-loop      (user-registered community loop)
        |     +-- ...                (your loop)
        |
        +-- selection
        |     explicit option > session route > preset route > default
        |
        +-- default driver
              +-- HeadlessDriver (vendored derivative of @deepseek-ai/dsh-agent-loop)

A strategy loop reuses a driver and installs an agent-scoped setup. It may declare a preferred driver (driver: 'loop2') or leave the choice to the caller. At creation time loop and driver are independent dimensions:

ctx.agents.create({ sessionId: 'a1', loop: 'strategy1', driver: 'loop1' })
ctx.agents.create({ sessionId: 'a3', loop: 'strategy3', driver: 'loop2' })

so one dock supports arbitrary driver × strategy combinations. A model-specific loop is usually a strategy loop: its author does not need to implement turn/step control flow.

An driver loop owns the complete createAgent / resume contract. It is for loops whose control flow differs from the default driver.

Install

Install as a normal DSH profile plugin (local checkout before publication):

cd /path/to/workspace
dsh plugin --profile web add ./dsh-loop-dock

Full usage instructions are in docs/usage.md and the DSH multi-agent compatibility matrix is in docs/compatibility.md.

The package declares dsh.bundle.patch = cordis.patch.yml. Its bundle patch disables the official agent-loop row and inserts agent-loop-dock, so the dock owns the single factory slot:

- id: agent-loop
  disabled: true

- insert:
    - id: agent-loop-dock
      name: 'dsh-loop-dock'
      config:
        defaultLoop: standard
        defaultDriver: default
        presetLoops:
          standard: standard
          minimal: standard
          code: standard
          cordis: standard
        sessionLoops: {}
        agents: []

    - id: agent-loop-dock-default-driver
      name: 'dsh-loop-dock/headless-driver'
      config:
        maxParallelToolCalls: 10
        fakeDriver: true

Do not install a strategy-loop pack and the official loop adapter into the same profile until the adapter is designed to leave setFactory to the dock.

Declarative agents

The dock accepts the agent list the official loop used, plus loop and optional driver fields:

agent-loop-dock:
  defaultLoop: standard
  agents:
    - id: planner
      provider: provider-a
      model: model-a
      loop: loop-a
      sessionId: planner-session

    - id: coder
      provider: provider-b
      model: model-b
      loop: loop-b

loop is optional. Without it, selection falls back through session routes, preset routes, and defaultLoop. driver is optional and falls back through route values, the strategy's declared driver, and defaultDriver. provider, model, maxTokens, reasoningEffort, and cwd are passed through to the driver and the strategy setup; consult your driver adapter for which fields it applies. A complete YAML shape lives in examples/agents.example.yml.

Driver picker in the web UI

The plugin ships a client bundle (client.js) that renders a "默认驱动 / Default driver" row in Settings → General, listing the drivers registered with the dock and persisting the choice to the agent-loops.defaultDriver setting. It talks to the agentLoops Remote service (listDrivers / setDefaultDriver). Full wiring details, the packaging requirements (junctions, exports, inject semantics), and behavioral notes (new sessions only, blank-session reuse) are in docs/usage.md.

Model routing is separate from loop routing

The dock owns two coordinates:

loop routing:  loop + driver
model routing: provider + model (+ maxTokens + reasoningEffort)

provider and model are consumed by DSH's LLM adapters; the dock passes them through, except loops that pin their own route (a loop registered programmatically with provider/model, e.g. the loop-ping debug adapter), which override the caller's choice — re-evaluated on every request against the session's effective preset, so preset switches follow live. So a four-agent team can be declared in one place:

agent-loop-dock:
  agents:
    - id: agent1
      provider: provider-a
      model: model-a
      loop: strategy1
      driver: loop1

    - id: agent2
      provider: provider-a
      model: model-a
      loop: strategy2
      driver: loop1

    - id: agent3
      provider: provider-b
      model: model-b
      loop: strategy3
      driver: loop2

    - id: agent4
      provider: provider-b
      model: model-b
      loop: strategy4
      driver: loop2

Can I create that team by typing in the DSH Web chat?

Not yet. The dock currently has no model-facing "create agent team" tool. The supported creation paths are:

  1. declarative agents config (above);
  2. programmatic ctx.agents.create({ agentOptions, loop, driver });
  3. DSH Web sessions created manually through the UI, where the model picker chooses the model and the preset picker chooses the mapped loop.

Built-in subagents inherit their parent preset, and DSH's subagent tool schema does not expose loop/driver fields. A natural-language team-creation tool is a natural next plugin on top of this dock, but it is not implemented yet.

Loop-provider protocol

See docs/loop-provider-spec.md. Start from examples/loop-author-template.

Strategy loop (the common case):

dock.register({
  id: 'community-loop',
  kind: 'strategy',
  description: 'community-owned setup for one model family',
  async setup(agentCtx) {
    // install presets, prompt sections, tool restrictions, event hooks
  },
})

Driver loop (custom control flow):

dock.register({
  id: 'planner-executor',
  kind: 'driver',
  async createAgent(ownerCtx, options) { /* ... */ },
  async resume(ownerCtx, options) { /* ... */ },
})

A default driver is installed once:

dock.registerDriver(headlessOfficialDriver)

Selection precedence

Create:

loop:   options.loop > sessionLoops route > presetLoops route > defaultLoop
driver: options.driver > route driver > preset driver
        > strategy.driver > settings defaultDriver > config defaultDriver

Resume:

  • the durable binding recorded at creation as agent-preset/selected data.agentLoopDock (both loop and driver, when the creation-time driver resolution produced one);
  • for sessions without that record, the durable SessionHeader.agentPreset mapped through presetLoops;
  • exact sessionLoops routes;
  • an explicit or routed choice that differs from the recorded/mapped binding is rejected with LOOP_SWITCH, mirroring DSH's blank-session-only preset switch rule.

The dock persists the binding through the KNOWN agent-preset/selected event, not through a custom event type. DSH's persistence read path refuses unknown event types unless they are marked ignorable, and Session.append has no public way to mark one. agent-preset/selected is already in DSH's known-event vocabulary; the dock stores its payload under data.agentLoopDock and preserves the session's effective preset in the same event, so DSH reads the session exactly as before.

Development

npm test
node examples/fake-two-loop.mjs
node examples/fake-two-driver-loops.mjs
npm pack --pack-destination /tmp
bash scripts/smoke-portable.sh /tmp/dsh-loop-dock-0.1.0.tgz

The regular suite skips the live API test. Opt in with a DeepSeek API key:

DSH_LOOP_DOCK_LIVE_API=1 \
DEEPSEEK_API_KEY=... \
DSH_LOOP_DOCK_LIVE_MODEL=deepseek-chat \
node --test test/live-api-2x2.test.mjs

The live test runs four real model turns across a 2×2 matrix: two headless drivers × two strategies.

fake-two-loop.mjs proves two strategy loops on one fake driver. fake-two-driver-loops.mjs proves two completely independent fake driver loops in one dock — the project's core claim without any real loop work.

The routing core (src/hub.mjs, src/selection.mjs, src/registry.mjs, src/config.mjs, src/errors.mjs, src/provider.mjs) has no runtime dependencies. The plugin entry targets DSH 0.1.0-rc.6 peers and uses the host-plane services through ctx.inject, ctx.effect, ctx.provide, ctx.agents.setFactory, ctx.llm.registerAdapter, and ctx.systemPrompt.variable; agent creation/resume delegates only through the documented AgentFactory contract.

License and attribution

MIT. The vendored official-loop derivative retains the upstream MIT license and lists all modifications; see NOTICE and vendor/dsh-agent-loop-headless/.

This is a community project, not an official DeepSeek project.

A brick, not the building

Routing is the easy part. The dock is deliberately small and boring — register, select, bind, delegate — any competent plugin author could write it in a weekend.

The hard part, and the reason this project exists, is that nobody has written a second agent loop yet. DSH made the Agent Loop a plugin — in my view, the only harness with that ambition — but the slot has stayed empty. This project is a dock: a working routing hub that proves the seam is real.

I believe DSH is the harness that can most easily push model × harness capability to its limit: a model's ceiling is not the model alone, but the model driven by the right turn structure, budget, and tool discipline. An extreme example: GPT-5.6 Sol and GPT-5.6 Luna sharing the same Codex loop would not both run at full strength; whether it is GLM-5.3, Kimi K3, or GPT-5.6, each deserves a dedicated DSH loop, just as a deepseek-v4-pro-class model benefits from a loop shaped for it. The future this project points to is multi-agent by default, where every agent picks the model best suited to it and the agent loop best suited to that model — one agent, one model, one model-specific loop — with DSH as the platform where the model × harness matrix is freely recombined.

I personally believe DSH is clearly moving in this direction, but it will take an extremely long time and an enormous amount of work — work that, in my view, only the open-source community can carry.