DeepSeek Harness plugin

dsh-routed-subagent

Global DeepSeek Harness plugin: subagent_routed — run a one-shot subagent fully mounted on ANY agent preset, from ANY session, with per-call model/provider override and a model-availability pre-check.

Jump to install

Source facts

Repository
bpc-oss/dsh-routed-subagent
Latest update
Aug 21, 2026
Category
Workflow & Automation
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/bpc-oss/dsh-routed-subagent
Plugin: dsh-routed-subagent
Author: bpc-oss

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.mdSource · read only

dsh-routed-subagent

!License !Version !CI

A global DeepSeek Harness plugin that lets any session dispatch a one-shot subagent fully mounted on ANY agent preset, with per-call model/provider override and a model-availability pre-check.

The stock subagent / subagent_fork tools force children to inherit the PARENT's preset. This plugin replaces that with a custom subagent provider whose async child setup calls agentPresets.mount(childCtx, <preset>) — so the child adopts the TARGET preset's complete composition: persona, prompt sections, skill catalog, and tools.

Features

  • Background by default, parallel dispatch — the call returns a job id immediately (like the stock subagent tool); the conversation stays free to do other work or dispatch more children in parallel, and aborting the conversation does NOT cancel the child (stop it with job_kill). Set run_in_background: false to wait inline.
  • Full preset mount — the child runs under the target preset's standing composition (not a persona copy): identity, mission section, skills, tools.
  • Per-call model overridemodel / provider arguments route the child's LLM call to a different model than this session's (via the official resolveChildAgentOptions channel).
  • Model pre-check — an invalid model fails fast with the provider's candidate list instead of an opaque child failure.
  • Official subagent ecosystem — one-shot lifecycle events, UI rows, trajectory; returns the child's final output.
  • Idempotent provider registration — multiple presets can mount the row; the host-plane provider registry is never duplicated.

External engines (engine=...)

subagent_routed can also dispatch the subagent to an external CLI agent instead of an in-harness preset mount. The default engine is dsh (this plugin's kernel); alternatives:

enginedriverbackground joblive progresskillexplicit modelcontinuable
dsh (default)preset-mount provider
codexcodex CLI app-server --stdio✅ (process event stream)turn/interruptthread/start model✅ same-thread resume
claudeClaude Code SDKabortController/close⚠️ official Anthropic API only
codebuddyCodeBuddy Code CLI --print✅ (NDJSON stream)✅ process kill--model--session-id / --resume
// external codex subagent (background, explicit model, live progress)
await subagent_routed({
  engine: 'codex',
  provider: undefined,       // external engines ignore the DSH provider
  model: 'gpt-5.6-sol',      // explicit codex thread model
  prompt: '...',
  run_in_background: true,
})
  • codex engine: keeps one long-lived codex app-server --stdio process (lazy start, init-once); each run uses thread/start + turn/start, live progress from item/agentMessage/delta events, kill via turn/interrupt, continuable reuses the disk-persisted thread (same threadId). Unattended default is approval_policy: never. The codex CLI must be logged in (codex login).
  • codebuddy engine: spawns codebuddy --print --output-format stream-json --include-partial-messages --dangerously-skip-permissions; live progress from text_delta events; continuable creates a session with --session-id <uuid> then resumes with --resume <uuid> (sessions persist on disk). Default model hy3 (overridable via config.codebuddyModel / $CODEBUDDY_MODEL). CodeBuddy Code CLI must be installed (codebuddy --version).
  • binary discovery: CODEX_BIN env wins (may point at native codex.exe or bin/codex.js); otherwise auto-probes the npm global @openai/codex/bin/codex.js.
  • claude engine: drives @anthropic-ai/claude-agent-sdk; model, kill, progress and background all work. ⚠️ continuable depends on the official Anthropic API — when the claude CLI is configured with a custom backend (e.g. AnthropicBaseURL pointing at a third-party/local endpoint), sessionId + persistSession may hang or be unusable; point AnthropicBaseURL at the official API for reliable resumes.

Distribution

GitHub-only. This plugin is not published to npm. Install it by mounting the package directory (see below). peerDependencies are declared with real semver ranges as metadata; they are not used for npm resolution.

Compatibility: targets DeepSeek Harness rc.7+ (behavior verified against rc.7 sources and rc.8 runtime) (the async child setup that this plugin relies on is a recent harness behavior).

Install

The plugin is a plain ESM package with a cordis.patch.yml bundle declaration.

1. Link the package into the harness install

The plugin statically imports @deepseek-ai/* packages, which resolve via Node ESM from the package location. Create a node_modules junction/symlink in the package directory pointing at the harness install:

:: Windows
mklink /J "<plugin-dir>\node_modules" "<harness>\resources\host\node_modules"
# POSIX (Linux/macOS)
ln -s "<harness>/resources/host/node_modules" "<plugin-dir>/node_modules"

2. Add the bundle to a profile

Add the package to your profile's dsh.profile.bundles list (e.g. <dshHome>/profiles/web/package.json):

{
  "dependencies": { "dsh-routed-subagent": "link:<plugin-dir>" },
  "dsh": { "profile": { "bundles": ["...", "dsh-routed-subagent"] } }
}

cordis.patch.yml in this repo is the bundle layer that registers the plugin; it is applied automatically when the package is listed in bundles.

> Tip: if your deployment provides a hot-assembly helper (e.g. a super-injector-style dev_install_package(dir=...)), you can use it instead of the manual steps above; restarts re-assemble from the bundles list either way.

Usage

subagent_routed(prompt="Use the dev engineer standard to review this repository", preset="dev", description="dev review")          # background one-shot
subagent_routed(prompt="Continue the review", preset="dev-reviewer", description="follow-up", fork=true)  # inherits THIS conversation
subagent_routed(preset="dev", prompt="Audit this repo", description="audit", continuable=true)            # send_message(<subagentId>, ...) later

Behavior:

Modes (one tool, four shapes):

modehowreturns
one-shot background (default)run_in_background: true (default)job id immediately; collect with job_output (live progress) / stop with job_kill; aborting the conversation leaves the child running
one-shot foregroundrun_in_background: falseblocks until the child returns its final output
forkfork: truejob id / run result — the child is seeded with this conversation's COMPLETED turns (inherits the context) then mounts the requested preset on top
continuablecontinuable: truedurable subagent id — continue it later with send_message(subagentId, ...); the child mounts the requested preset and keeps it across resumes

Parameters:

inputbehavior
preset invalid / unresolvableerror, with the roster's available preset ids
model / providerper-call model override (fail-fast pre-check lists the provider's candidates; original error preserved as cause)
max_tokensoutput/token cap for the child's LLM calls (positive integer)
tool_filterDENY-only tool mask on top of the preset's tool surface ({ deny: string[] }, e.g. deny shell tools for a read-only audit)
max_depth not a positive integertool-layer validation error
fork + continuable togethersupported (continuable fork seeds the parent's completed turns)
valid callchild fully mounted on the target preset

How it works

1. A custom subagent provider (routed-mount) re-implements the official one-shot in-process driver (dsh-subagent-in-process-driver's startInProcessRun) with one load-bearing change: the child setup is async and awaits agentPresets.mount(childCtx, targetPreset) instead of composing from the parent. 2. agents.create awaits the setup (verified in dsh-agent-loop), so the async mount runs inside the unpublished creation window; a failure rolls the whole child back. 3. The child's session header records agentPreset: <target> (overriding the parent value), so cold reads rebuild the child under the composition it actually ran. 4. The tool settles the run in two sequential fault-tolerant phases — result first, then dispose — matching the official settleForegroundRun ordering (racing dispose against result would skip the child's turn and return "aborted").

Known limitations

  • preset generation drift (known limitation)mount re-resolves the preset by id on every creation/resume, so editing a preset file between continuable turns hands later turns a NEWER generation of that preset (the official composeFrom path joins the parent's exact standing instance instead). Documented behavior; restore the preset to its original state to keep turns consistent.
  • Failure semantics — like the official foreground subagent tool, a child that ends with error / refusal / max-tokens makes the tool call THROW (with any partial output attached); only completed and caller-initiated aborted return as values. Low-level LLM error details live in the child session log.
  • Pre-check is conditional — the model pre-check runs only when the harness exposes an llm service AND a provider route exists (explicit provider or the parent's). Without either, it is skipped and the call proceeds.
  • Provider availability is environment-specific — the pre-check validates against the runtime model catalog, but a reachable provider with a valid key is still required for the call to succeed.

Platform patch (continuable + preset mount)

continuable mode mounts the requested preset on the child and keeps it across resumes — that required a small, additive patch to the open-source @deepseek-ai/dsh-subagent:

  • install-level junction (single assembly point): resources\host\node_modules\@deepseek-ai\dsh-subagent → the patched fork (the original package is backed up beside it). The plugin's startup assertion logs a loud warning if the loaded instance is not the patched fork — continuable+preset will silently degrade to the parent composition, so check the log on upgrade. Do NOT add a profile-local link: dependency to @deepseek-ai/dsh-subagent (that would split module identity and defeat the patch).
  • patch surface (additive only — official paths with no preset are byte-identical):

- applyChildComposition: composition.preset mounts the TARGET preset instead of joining the parent's (composeFrom skipped — a second bind would throw; delegation context / persona / toolFilter kept); appends agent-preset/selected(target) so fork seeds replaying the parent's selection events cannot shadow the header on cold rebuild - materializeTracked setup is async (awaited by the agent factory) and still returns the { commit } contract - continuable descriptors gain an optional preset field (version 2 → 3 for continuable only; one-shot stays 2 — a rollback rejects v3 descriptors cleanly as NOT_RESUMABLE, and legacy v2 continuable descriptors still parse) - coldResume rebuilds the child under the SAME preset from descriptor.preset; a missing/broken preset surfaces a named-preset error instead of a generic "unavailable"

  • rollback: delete the install junction (resources\host\node_modules\@deepseek-ai\dsh-subagent), copy <fork-dir>\@deepseek-ai\dsh-subagent.orig back into place, restart — official behavior returns (pre-existing preset-continuable children become NOT_RESUMABLE, as designed). Note: keep the fork directory present if any other profile tree junctions to it (dsh-continuous-worker\node_modules\@deepseek-ai\dsh-subagent) still exist, or re-point them.

Disabling the stock subagent tools

Once the full stock surface is ported, subagent_routed becomes the single delegation entry point: a global tools.guard denies subagent / subagent_fork at execution with a redirect message (config.disableStockSubagent ?? true; set false to keep them). Scope: every preset that mounts this plugin row.

Development

node --check lib/index.js   # syntax

The plugin is a plain ESM package (zero build step): lib/index.js plus per-engine providers under lib/engines/. CI runs node --check on every push.

License

MIT