DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Capability Composer — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
C

dsh-capability-composer

Capability Composer

DSH plugin: shrink what the model sees, not what runs. Composes plugins and skills into named sets resolved per session / workspace / global. Only the core tools plus the meta-tools (search_plugins / load_plugin / invoke_tool) stay resident; everything else is reached on demand. Plugins and skills k

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:xiamubumu/dsh-capability-composer#b3a1c6588ad406e00173542f560af68f32903af6
READMECompatibilityVersions
Skill compositionsSkill scope

Description

DSH plugin: shrink what the model sees, not what runs. Composes plugins and skills into named sets resolved per session / workspace / global. Only the core tools plus the meta-tools (search_plugins / load_plugin / invoke_tool) stay resident; everything else is reached on demand. Plugins and skills keep running — only the catalog shrinks.

Compatibility and provenance

Capability Composer is published as dsh-capability-composer and currently resolves to version 1.0.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/14/2026

Versions

1.0.0stable
10/14/2026

Related plugins

Loading related plugins…

Latest
1.0.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/15/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in agents-orchestration.

Headless@deepseek-ai/dsh-headlessThe dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layerExperimental Agent Team Profile@deepseek-ai/dsh-experimental-agent-team-profileAgent Teams collaboration, tools, and Web UI in one experimental bundleExperimental Ralph Bundle@deepseek-ai/dsh-experimental-ralph-bundleRun explicitly requested repeated work with fresh agents.Hindsight Coding Agents@vectorize-io/hindsight-coding-agentsReflect-only Hindsight long-term memory for coding agents (harness-pluggable: opencode, …), with automatic background ingestion (no setup CLI).

README

dsh-capability-composer

English · 简体中文

Shrink what the model sees, not what is running.


Table of contents

  • What this is
  • What it does (four mechanisms)
  • How a composition is resolved (three levels)
  • UI
  • Screenshots
  • Configuration
  • HTTP API
  • 🔗 Integration
  • Known limitations (stated plainly)
  • Installation
  • Compatibility
  • FAQ
  • Repository layout
  • Self-check
  • License

What this is

By default DSH stuffs all of the following into every single request:

What gets stuffed inMeasured size
Tool schema registered by every installed plugin414 tool definitions / ~65.6K tokens
The catalog of all skills~76K tokens as a baseline
The system-prompt section registered by each pluginagent-teams:usage ≈1296 tok + plugin:dsh-docker ≈579 tok + plugin:api-client ≈254 tok

Every request pays for "the things you might use", while only a few of them are actually useful in this turn.

dsh-capability-composer groups these into compositions, and only lets the current composition into the context.

What it does / what it does not do

Let's make the boundary clear first, because this is where misunderstandings happen most easily:

✅ It does❌ It does not
Narrow the plugin catalog the model seesNever turns off any plugin — plugin processes keep running, the UI keeps showing them
Shadow skill catalog entries that are not on the listNever removes skills — /skill-name can still be invoked manually
Make tools non-resident by default (keeping only the core + meta tools)Does not restrict execution — invoke_tool can call anything by default
Prune the system-prompt sections registered by plugins, according to the compositionDoes not touch committed history
Resolve compositions at the session / workspace / global levelsDoes not modify any third-party plugin file on disk

In one sentence: it shrinks "the catalog the model can see", not "the things that are running". Plugins keep running, skills stay available, tools stay callable — all that changes is how much gets stuffed into each request.


What it does (four mechanisms)

① Tools are non-resident by default

Only 31 are resident: the 28 official core tools, plus 3 meta tools — search_plugins / load_plugin / invoke_tool.

All other tools never enter the tools list. The model sees them in the catalog section of the system prompt (section heading # 可用插件与 MCP 工具), and calls them directly when needed:

invoke_tool({ tool: "mcp__vnpy__run_backtest", args: { ... } })

Use load_plugin when a whole group needs to be loaded:

load_plugin({ ids: ["mcp:vnpy"] })

The granularity is "plugin", not "tool name". This is deliberate: finer granularity was tried — after 417 / 211 tool names were compressed away, the model had no idea what to search for, which made things harder to use instead. The granularity now is the plugin.

Mounting it prints one log line saying so:

工具按需加载已挂载:常驻白名单 28 个 + 元工具 3 个(其余全部按需;组合只决定可见范围)

② Skill shadowing (not disabling)

A skill that is not in the current skill composition gets a shadow entry with the same name registered:

  • invocation.modelInvocable: false — does not enter the skill catalog the model can see and auto-invoke
  • rank: 0 — the lowest rank wins, shadowing the original skill

/skill-name can still be invoked manually.

One shadow entry is mounted at the global level, and every agent gets one more at the "nearest level", so that session-level compositions also take effect at the agent dimension.

③ Plugin compositions narrow "the model's plugin catalog"

Narrowing happens when the catalog section is generated, not by unloading plugins.

There are two lines that are never narrowed:

  • MCP server lines — one line per MCP server; the tools inside a server are not governed by compositions
  • The "unassigned tools" fallback line — tools that cannot be attributed to any plugin are always kept

④ System-prompt sections registered by plugins are pruned by composition too

Plugin compositions cannot control "the system-prompt sections a plugin registers for itself" — those are inserted by the plugin itself in system-prompt/assemble, and are a different thing from the catalog section.

This plugin's prunePluginSections() is the only place that can prune them according to the current plugin composition.

Measured saving: ≈2129 tokens / request:

SectionSize
agent-teams:usage≈1296 tok
plugin:dsh-docker≈579 tok
plugin:api-client≈254 tok

Fail-open design — better to prune too little than to prune by mistake:

  • A section whose owner cannot be identified is always kept
  • A section without a namespace is always kept
  • When the visible plugin list is empty, nothing is pruned, and the log records 「没有『不在组合里』的依据,宁可留着」
  • When the plugin list cannot be obtained, nothing is pruned either

Every drop prints one line of evidence to the log.

It can be turned off with DSH_COMPOSER_PRUNE_PLUGIN_SECTIONS=0.


How a composition is resolved (three levels)

The rule is "the nearest level that specifies something wins" — not a strict override.

LevelDescription
1. Sessionspecified for the current session alone
2. Workspacespecified for the current working directory (cwd)
3. Globalpinned[axis]['*']

A few easy-to-get-wrong points:

  • An empty string / an empty array / null all count as "not specified" and keep inheriting from the level above — they do not mean "specified as empty"
  • A single level can select several entries; the union is taken
  • An empty list = no filtering (not "select none"). To select none, use __none__

The UI shows which level the current one comes from: 『当前会话』 / 『当前工作区』 / 『全局』 (Session / Workspace / Global).


UI

It installs into DSH's Settings → Plugins, adding two tabs:

Plugin compositions

Decides which plugins appear in the model's plugin catalog.

Skill compositions

Decides which skills appear in the model's skill catalog. You can create a composition, rename it, delete it (with a second confirmation), rename a series, delete a series, select all / select none, and search skills.

Changes take effect immediately, no restart needed

  • UI changes are debounced by 400 ms, then POST /dsh-capability-composer/state
  • After the host writes to disk, the state is refreshed immediately

Saving merges item by item per composition name, not a whole-state overwrite

The server state is the base; only composition names that actually exist in the local draft are overwritten. So a composition created elsewhere will not be accidentally deleted by this UI.

The trade-off: a composition deleted here will be "resurrected" if it still exists on the server. This is a deliberately conservative direction — losing a composition costs far more than keeping one extra composition.


Screenshots

Skill compositions page

Manage which skills each composition contains under Settings → Plugins → Skill compositions, and which level 「这里用」 ("Use here") applies to.

Skill compositions

Skill scope

Organize skill compositions by series, and use the dropdown to pick which set the current session / current workspace / global each use.

Skill scope


Configuration

State file

There is exactly one:

<DSH_HOME>/capability-composer/compositions.json

The resolution order for <DSH_HOME>:

PlatformPath
AllDSH_HOME environment variable (takes priority)
Windows%APPDATA%\dsh-desktop\harness
macOS~/Library/Application Support/dsh-desktop/harness
Linux$XDG_CONFIG_HOME/dsh-desktop/harness or ~/.config/dsh-desktop/harness

If none of them exists, it errors out and exits — it never guesses a hard-coded path and silently writes into it.

A compositions.json.bak backup is made automatically before every write.

Two other runtime files (both are caches; delete them and they are rebuilt automatically):

FilePurpose
capability-composer/entry-id-map.jsoncache from package name → entry id
.composer-resident-toolsthe auto section of the resident tool list

First install starts empty

A fresh machine gets defaultState() — four empty slots, no compositions, no pins. No seed and no "starter pack" is shipped: every composition in such a file would be somebody else's, and a new user opening the composer must not find arrangements they never created.

Your existing compositions.json is never overwritten and never cleared — an empty state is written only when the file is absent or unreadable.

Environment variables

This plugin has no cordis config; everything is tuned through environment variables.

VariableDefaultEffect
DSH_COMPOSER_MIDDLEWARE_FULLonfull pass-through on the execution side (invoke_tool can reach MCP tools and tools of dependency agents)
DSH_COMPOSER_TOOL_SEARCHonregister the search_plugins searcher
DSH_COMPOSER_PRUNE_PLUGIN_SECTIONSonprune the system-prompt sections registered by plugins, according to the composition
DSH_COMPOSER_CATALOG_FALLBACKonfallback source for catalog data
DSH_COMPOSER_CACHE_SAFEoncache-safe mode
DSH_COMPOSER_GUARDonguard check
DSH_COMPOSER_DIAGondiagnostics log
DSH_COMPOSER_AUTOLOAD_MAX0auto-load limit
DSH_COMPOSER_SHRINK_ENTRIESoffcatalog entry shrinking
DSH_COMPOSER_HISTORY_REWRITEoffhistory rewrite
DSH_COMPOSER_RESIDENT_BUDGET—resident budget
DSH_COMPOSER_RESIDENT_FILE—resident tool list file
DSH_COMPOSER_EXTRA_TOOLS—extra tools to keep resident
DSH_COMPOSER_RESIDENT_EXCLUDE—resident exclusion list
DSH_SEMGREP_SHORT_PATHC:\dshsesemgrep short-path junction (see below)

About DSH_SEMGREP_SHORT_PATH: this is the only absolute path with a default value in this plugin's runtime code. It has to match the junction path hard-coded by the semgrep plugin patch in the marketplace, otherwise that patch cannot self-heal. It can be overridden with an environment variable; when semgrep is not installed, the relevant function simply returns not-installed — it is code that never executes.


HTTP API

Prefix /dsh-capability-composer.

MethodPathDescription
GET/stateread the snapshot
GET/skillslist skills
GET/effective?sessionId=&cwd=the effective list after three-level resolution
GET/catalogplugin catalog (for the composition picker)
POST/statewrite state

Security

  • Anything non-loopback is 403 (loopback only)
  • A failed Origin check is always 403 (origin not allowed) — local tools that send no Origin are let through

POST /state has a hard gate

The body must carry either compositions or pinned, otherwise it is rejected with 400:

拒绝写入:body 必须是状态对象(或 {state: ...}),且至少带 compositions / pinned —— 免得一个空 body 把组合清空 [refusing the write: the body must be a state object (or {state: ...}) and must carry at least compositions / pinned — so that an empty body cannot wipe the compositions]

This gate was added after a real incident: a {state: {…}} wrapper was once POSTed by mistake, wiping 9 plugin compositions + 21 skill compositions.


🔗 Integration

With dsh-composer-launcher

Without this plugin, the launcher does not break.

The launcher has an integration table that probes GET /dsh-capability-composer/state:

CaseLauncher behavior
Probe succeedsshows 「按组合收窄 N / 共 M 已装插件」 ("shrunk by composition N / M plugins installed"); the picker can read the composition contents
Probe failssilently skipped — the integration list just shows HTTP xxx, and plugin names fall back to rendering the package name

The source comment, verbatim: 「有就连,没有就静默跳过(不存在是正常状态)」.

Conversely, without the launcher this plugin works as usual — this plugin never probes the other side; the other side probes it.

With dsh-mcp-manager-ui

This plugin does not manage MCP, and does not read the MCP panel's data.

Only two things relate to MCP:

  1. Excluding the MCP panel from its own plugin catalog — dsh-mcp-panel / dsh-mcp-connector / dsh-mcp-manager-ui / dshmarket / dsh-client-ui-settings-plugins and this plugin itself never enter the "plugins managed by compositions" list
  2. Generating one line per MCP server in the catalog section (id looks like mcp:<server>), so the model can load the whole group with load_plugin({ ids: ["mcp:<server>"] }) when needed

This line is never narrowed by compositions.

The exact wording of that hint in the UI:

MCP 工具完全不受这里影响,归 MCP 面板自己管。

Without the MCP panel nothing happens — it is not in the dependencies.

With dsh-context-reclaim

The two plugins do not depend on each other, but their responsibilities complement each other.

The prunePluginSections() capability lives in this plugin because compositions cannot control the system-prompt sections a plugin registers for itself — that has to be done in a place that can see both "the current composition" and "the fully assembled prompt", and this plugin happens to be that place.

Installing this plugin alone, without reclaim: everything works normally, except that tool results are not sanitized / bounded.


Known limitations (stated plainly)

  1. Tool attribution is guessed by scanning source string literals; it is not an authoritative mapping. That is why /state carries three honest annotation fields: exact (exactly determined), uiOnly (only used in the UI), scanCertain (scan confidence).
  2. The first scan of the plugin catalog takes about 5 seconds; after that it goes through the entry-id-map.json cache.
  3. Auxiliary calls that do not pass purpose are classified as the main route and are not affected by degradation.
  4. GET on /state has a side effect: with ?_probeKeys= it writes the reported real keys into the auto section of .composer-resident-tools (it only writes the file; a restart applies it).

Installation

From the DSH plugin marketplace

Search for capability composer in the marketplace and click install.

From GitHub

dsh plugin --profile web add github:xiamubumu/dsh-capability-composer

From a local directory

dsh plugin --profile web add /path/to/dsh-capability-composer

⚠️ Do not use npm install / junction / link

This plugin ships install.mjs and install.ps1; the comment inside states the reason:

不走 Junction —— Junction 会被 DSH 的 projectGenerations() 静默丢掉字段,重启后 link 与依赖项一起消失,插件整个不可见,日志里一行都没有。 [do not go through a Junction — DSH's projectGenerations() silently drops fields, so after a restart the link and its dependencies disappear together, the plugin becomes entirely invisible, and not a single line shows up in the log.]

The correct approach is to copy it into a generation entity + write generation.json / desired.json + call the official projectGenerations().

Restart DSH after installing

Host plugins and patches are loaded only at startup.

After installing, changes in the workspace do not take effect automatically

install.mjs states it clearly: 「从此工作区里的改动不会自动生效,改完要重跑一次本脚本」.


Compatibility

ItemRequirement
DSHthe 1.5 series (>=0.1.5-rc.2 <0.2.0). Later DSH versions will be followed up
DSH Desktop✅
DSH Web✅
As long as it is DSH✅ everything works
Windows / macOS / Linux✅
Node20+ at the syntax level; but you do not need to install it yourself — DSH Desktop bundles the runtime, and the plugin is loaded into that runtime
Runtime dependencieszero

FAQ

Can a composition "turn off" a plugin to save memory or CPU?

No. There is no action that turns a plugin off.

Plugins load as usual, run as usual, and appear in the UI as usual. The only thing saved is context — the catalog section and the system-prompt sections get shorter, and each request pays fewer of those tokens.

If a plugin is not selected in a composition, can its tools still be called?

Yes. What a composition narrows is "the catalog the model can see", not execution permission.

By default DSH_COMPOSER_MIDDLEWARE_FULL is on, so the execution side is unrestricted — invoke_tool can reach MCP tools and tools of dependency agents.

If a skill is not in the composition, is it disabled?

No. The skill is still registered; it just does not enter the skill catalog the model can auto-discover (modelInvocable: false).

The slash command /skill-name can still be invoked manually.

I changed a composition in the UI — do I need to restart DSH?

No. It is saved automatically after a 400 ms debounce and takes effect immediately.

Is there a config file for tuning parameters?

No. This plugin reads no cordis config at all (cordis.patch.yml contains only a 5-line insert).

Everything tunable is an environment variable; see the table above.

Does this plugin support MCP management? Does it ship an MCP panel?

Neither. The MCP panel is not its.

The panel you see under "Capabilities → MCP" is another plugin's UI. This plugin does only the two MCP-related things: excluding the MCP panel from its own plugin catalog, and generating one line per MCP server in the catalog section.

Can the UI follow the DSH language setting?

Yes. The copy lives in two tables (140 keys each) and the plugin reads the host's locale service, so switching the DSH language switches the UI live. Adding a third language is a registerLanguage(id, table) call — the registry is not hard-coded to these two.

Is the tool-to-plugin mapping accurate?

It is guessed by scanning; it is not an authoritative mapping. That is why the API carries three honest annotation fields: exact / uiOnly / scanCertain.

It is accurate in the vast majority of cases, but do not use it as authoritative data.


Repository layout

dsh-capability-composer/
├── cordis.patch.yml        插件挂载入口(5 行)
├── package.json
├── lib/
│   ├── index.js            宿主半边:状态、HTTP 接口、目录生成、段裁剪
│   └── client.js           客户端半边:设置里那两个页签
├── install.mjs             安装脚本(不走 Junction)
├── install.ps1             Windows 用
├── screenshots/
├── verify.mjs              自检
├── README.md               English (this file)
└── README.zh-CN.md         Simplified Chinese

Self-check

node verify.mjs

Zero dependencies, offline, writes nothing to disk. It checks manifest fields, entry syntax, leftover secrets, and hard-coded absolute paths.


License

MIT © 夏目 (xiamubumu)