DeepSeek Harness Plugin

fan56/dsh-subagent-registry

Stars ★ 6 Downloads (30d) 3,327 Category Tools & Capabilities Added 2026-08-28 npm @aiwayds/dsh-subagent-registry

Register locally-defined custom agents as callable subagents in dsh: the main conversation invokes any agent by name via use_agent, each running as a real dsh subagent with its own persona. Supports breakpoint resume for interrupted runs.

Install

# from npm (prebuilt)

dsh plugin --profile web add @aiwayds/dsh-subagent-registry

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:fan56/dsh-subagent-registry

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

中文

Register locally-defined custom agents (~/.dsh/agents/*.md) as callable subagents in dsh — the main conversation invokes them by name through use_agent, background runs take follow-ups via ask_agent, and interrupted runs resume from their saved partial work. No host patching, no code — a markdown file per agent.

Why

  • One markdown file is one agent — frontmatter carries the model/thinking settings, the body is the system prompt, changes take effect immediately.
  • Resumes interrupted runs — after an error, cancellation, token limit or crash, the next call for the same agent continues from the saved partial work instead of starting over.
  • Background dispatch + two-way follow-ups — background: true runs the agent as a durable background conversation while the parent keeps working; ask_agent sends a follow-up and waits for the reply.
  • Three personas out of the box — workhorse / oldfox / rubber-duck are seeded on first start (see below).
  • Built on the official subagent machinery — no reimplementation: every custom agent starts through dsh's stock spawn provider, so each child is a real dsh subagent (full session, persistence, continuable). New capabilities in the official subagent stack (bidirectional messaging, say) are inherited automatically; the native subagent tool keeps working alongside — the two coexist without interference.
  • Pure plugin — only relies on dsh ≥ 0.2.0-rc.2's public subagent machinery; uninstalls cleanly at any time.

The three shipped agents

Seeded into ~/.dsh/agents/ on first start (only when the directory holds no parsable agent — your edits are never overwritten). All three are ordinary markdown files: edit them freely.

Agent Role Example
workhorse (牛马狗) The workhorse: writes code, investigates, tests, deploys — all the grunt work; default deepseek-flash, guarded against dangerous operations "Use workhorse to turn the release checklist into a table"
oldfox (老法师) The advisor who doesn't build: analysis, trouble shooting, review, audits — checks, never implements; glm-5.3 "Have oldfox review this design"
rubber-duck (小黄鸭) Multimodal visual agent: reads screenshots / charts / handwriting, draws plotext / mermaid / matplotlib figures; runs on an image-capable model "Use rubber-duck on this screenshot, extract the page text"

Usage

Install, restart dsh, then just ask in the conversation — the main model picks the agent by name:

Use workhorse to turn today's release checklist into a table

Under the hood that is use_agent(agent: "workhorse", prompt: "…"). For background runs, follow up with ask_agent(agent: "worker", message: "…") — it waits for the reply.

Define your own

Drop a file into ~/.dsh/agents/:

---
name: my-agent
description: "One-line subtitle shown in the use_agent roster"
model: opencode-go/deepseek-flash
thinking: high
---

You are my-agent. This markdown body is used verbatim as the system prompt.

Frontmatter keys: name (required), description, display_name, model (provider/model; absent = inherit), thinking (off/low/medium/high/max; absent = inherit), deep (0 = leaf, may not spawn subagents; default 1), background (true = dispatch in the background by default). Unknown keys are silently ignored.

Concurrency and round limits (since 0.1.7)

Concurrency and nesting depth are owned by the official dsh-subagent service — this plugin keeps no concurrency counter or queue of its own (the official ActivationManager schedules): maxActiveSubagents (live-children cap, default 8) and maxDepth (delegation-depth cap, default 1). Both are volatile fields, tunable without a restart — via a profile patch subagent: { maxActiveSubagents: N, maxDepth: M } or at runtime with settings.update('subagent', …). The use_agent deep frontmatter only tightens within that official depth budget (deep: 0 leaves strip every agent-spawning tool outright).

maxRounds (a per-agent turn budget) stays: the official subagent seam has no round-budget capability, and the key is still consumed by the host TUI's hard-stop ladder.

→ Full reference: docs/AGENT-FORMAT.md — every key's validation and failure modes, deep/thinking semantics, resume mechanics, background dispatch, configuration fields, known limitations.

Bundled skill

The plugin ships a bundled skill named dsh-subagent-registry-config. Whenever the conversation touches custom subagents, agent .md authoring, resume semantics, or this plugin's configuration, dsh loads the bundled usage & configuration guide, so the model can write agent files for you (collecting choices via ask_user_question) and adjust the plugin config without digging through the README. The skill is versioned and published with the package (skills/dsh-subagent-registry-config/SKILL.md).

Installation

Requires dsh >= 0.2.0-rc.2 (the RC/stable line; the alpha line is not supported).

Option A — mount a checkout into a dsh profile:

dsh plugin --profile tui add ~/github/dsh-subagent-registry

Option B — npm dependency: npm i @aiwayds/dsh-subagent-registry, then load the plugin under the stable id dsh-subagent-registry in your profile's config, or mount it through a bundle patch (see cordis.patch.yml in this repo for the pattern).

Uninstall

dsh plugin --profile <name> remove @aiwayds/dsh-subagent-registry

The host splices the plugin out of the profile; restart dsh and the use_agent / ask_agent tools are gone. Your agent files in ~/.dsh/agents/ stay — they are user-owned and never re-seeded or overwritten. dsh-tui-pi degrades gracefully without this plugin (you just lose custom-agent dispatch).

Development

npm run check    # tsc --noEmit
npm run build    # tsc -> lib/
npm test         # all unit tests (no LLM, no network)

The @deepseek-ai/* dependency contract (why optional peers)

This repo declares the @deepseek-ai/* packages (cordis, dsh-subagent, dsh-llm, schemastery, …) as optional peerDependencies only (>=0.2.0-rc.2). That is a deliberate two-layer split:

  • Release semantics (for consumers): the declaration says "use the host's own copies, floor >=0.2.0-rc.2". Optional peers are never auto-installed by pnpm or npm, so they cannot materialize a second copy in the profile's node_modules that shadows the host's bundled closure. What does break hosts is a hard dependency pinned to an old rc — that can render a 0.2.x host unbootable (a known community failure mode).
  • Dev typecheck (for this repo): since peers are not installed, scripts/link-dsh-closure.mjs (postinstall) symlinks node_modules/@deepseek-ai/* to the global dsh install's closure, keeping exactly one @deepseek-ai/cordis in the type graph — a second copy breaks the cordis declare module augmentation (Property 'settings' does not exist on type 'Context').

Maintenance rule: keep these entries as optional peers — never move them back to dependencies/devDependencies, and never drop optional: true (a non-optional peer is auto-installed under pnpm's auto-install-peers and the second-copy breakage returns).

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.