Turn anything into a DeepSeek Harness plugin.
One pipeline, one compiler, one verifier — for the harness where everything is already a plugin.
An agent-native compiler and verification pipeline that turns software capabilities into installable, tested, and verified DSH plugins.
The claim is in the name, and a claim like that is worth what its weakest category is worth. Each category is a small but real representative, run through the whole deterministic pipeline — IR → compile → static gate → build → typecheck → package integrity:
Git CLI ██████████ PASS
Python CLI ██████████ PASS
npm CLI ██████████ PASS
Local Script ██████████ PASS
GitHub Repository ██████████ PASS
OpenAPI ██████████ PASS
MCP Server ██████████ PASS
Pipeline coverage 15 / 15 stages mechanized
Runtime acceptance PASS (accept → accepted, with evidence)
Package integrity PASS (every promised entry is in the artifact)
node --experimental-strip-types scripts/golden-e2e.mjsThe table above is generated by that command and pinned by scripts/check-readme-status.mjs — a
hand-maintained status table drifts, and a drifted one is read as current.
MCP's PASS is a refusal, and that is the correct outcome. An MCP server already has a supported route
into dsh; generating a plugin for one duplicates that route. Its golden case asserts the compiler refuses
it and names the route to use instead — a category that "passed" by emitting a redundant plugin would be a
regression, and bundle/src/compile.ts throws to prevent it.
bundle/src/pipeline.ts carries twenty stages, each with an owner and the reason
for that owner. Coverage is computed from it, never asserted:
| Owner | Meaning | If it has no tool |
|---|---|---|
deterministic |
Has a correct answer, or a contract that cannot be re-derived per run | A hole |
runtime |
Reachable only through a running harness | A hole |
agent |
Requires judgement | Correct — mechanizing it replaces intelligence with a heuristic |
external |
Owned outside this project | Nothing; named so the pipeline has no silent gap |
Eight tools cover fifteen stages, because a verdict like acceptance is one decision made of seven checks.
The coverage number is the thing to watch — not the tool count. docs/pipeline.md is
the full map.
DeepSeek Harness (dsh) is built on vendored Cordis,
where everything is a plugin: the model adapter, the tool registry, the session log, and the agent loop
itself. There is no privileged core, and every part is replaceable from cordis.yml.
dsh-plugin-anything is the missing on-ramp to that architecture. Given any operable target — an external
CLI, an HTTP/REST API, a local service — it produces an installable plugin bundle that a dsh agent can
load, call, and still have after a restart.
It is a deliberate isomorphic mirror of CLI-Anything: the same
phase-by-phase methodology, the same "use the real system, don't reimplement it" iron rule, the same
registry packaging — with every landing point translated into dsh's native concepts.
| CLI-Anything | dsh-plugin-anything |
|---|---|
| GUI software → agent-usable CLI | anything → dsh plugin bundle |
HARNESS.md 8-phase SOP |
the same 8 phases, dsh landing points |
core/ + utils/<sw>_backend.py |
src/ + src/provider.ts (the single egress module) |
click + REPL |
defineTool + ctx.tools.register |
SKILL.md |
SKILL.md (dsh frontmatter) + a mount row |
setup.py → PyPI |
package.json → npm / tarball / git |
registry.json + cli-hub |
the existing market registry — reused, not rebuilt |
dsh already ships a loop that generates plugins from a request: the cordis agent preset mounts
tool-cordis, and the model can inspect its own runtime, write a package, and run it. That loop is
excellent for exploration and useless for delivery:
Dynamic packages live only in the shared DSH process memory. […] They create no Plugin file, install no package, change no
cordis.ymlor personal/project configuration, do not survive restart, and cannot be promoted automatically. —packages/extensions/tool-cordis/README.md
The gap is not generation. It is promotion — turning something that works for one session into a bundle that persists, installs, and distributes. That, plus the SOP, templates, verifier, and CI discipline around it, is what this project provides.
dsh-plugin-anything/
├── kit/ # the SOP kit — the single source of truth for how a bundle is built
│ ├── HARNESS.md # the 8-phase methodology. Read this before anything else.
│ ├── commands/ # /plugin-anything, :list, :refine, :test, :validate
│ ├── guides/ # progressive disclosure — one guide per deep area
│ ├── templates/ # the files a generated bundle is assembled from
│ ├── scripts/verify-plugin.mjs # the static gate
│ └── tests/ # the gate's own acceptance tests
│
├── bundle/ # the npm package: the plugin_anything_* tools
│ ├── src/ # tools.ts, pipeline.ts, ir.ts, compile.ts, inspect.ts, accept.ts, pack.ts
│ ├── tests/ # 141 tests over the whole surface
│ ├── scripts/ # accept-bundle.mjs, package-bundle.mjs, typecheck-example.mjs, render-example.mjs
│ ├── templates/ sop/ skills/ docs/ # shipped copies of what the tools read at runtime
│ └── cordis.patch.yml # the bundle's patch layer
│
├── examples/
│ ├── golden/ # one real representative per target category
│ └── dsh-plugin-git/ # a generated bundle, rendered from the templates
│
├── registry/ # the awesome-dsh-plugin entry, and the metadata that format lacks
├── notes/ # Agent Notes — the decisions, and what was rejected
├── scripts/ # the acceptance ladder, the golden E2E, three consistency checks
├── docs/ # pipeline.md, runtime-acceptance.md, and the archived plan
└── .github/workflows/ # CI: gates, golden E2E, composition against a real dsh
Two of those directories matter for distribution, and only one of them is published:
| Directory | What it is | How it ships |
|---|---|---|
bundle/ |
The npm package dsh-plugin-anything-bundle |
cd bundle && npm publish — installed by dsh plugin add |
kit/ |
The SOP, templates, and gate | Nothing to publish. It is what this repository's own tooling and agents read. |
# 1. Read the SOP. It is the authority on every phase.
# kit/HARNESS.md
# 2. Gate a generated bundle statically.
node kit/scripts/verify-plugin.mjs examples/dsh-plugin-git
# 3. Install and verify composition.
dsh plugin --profile dev add ./examples/dsh-plugin-git
dsh --profile dev --dump-config | grep -A3 '# == dsh-plugin-git'
# 4. Boot it, use the tools, then RESTART and use them again.
# Surviving the restart is the whole point — it is what a dynamic package cannot do.
dsh --profile devThe methodology, templates, and gate that produce installable bundles. A generated bundle is an output of it, and nothing here is derived from a generated bundle.
| Path | What it is |
|---|---|
HARNESS.md |
The 8-phase SOP. Read it before anything else. |
commands/ |
Slash commands that execute the SOP: /plugin-anything, :list, :refine, :test, :validate |
guides/ |
Progressive disclosure. Each guide is loaded on demand, never up front. |
templates/ |
The files a generated bundle is assembled from — manifest, patch, plugin entry, provider, tool, build config, skill |
scripts/verify-plugin.mjs |
The static gate. Catches what fails silently. |
tests/verify-plugin.test.mjs |
The gate's own acceptance tests — every check against a mutant that must fail |
Loaded when a phase reaches them, not before.
| Guide | Read it when |
|---|---|
seam-vs-consumer.md |
Deciding the plugin's shape (§3). Default: Consumer. |
backend-cli.md |
The target is an external CLI binary |
backend-http.md |
The target is an HTTP/REST API |
backend-mcp.md |
The target speaks MCP — usually you should not generate a plugin at all |
tool-contract.md |
Writing a tool: the definition object, the schema DSL, render intent, the execution pipeline |
skill-authoring.md |
Shipping a SKILL.md, and the baseUrl trap in mount rows |
in-tree-vs-out-of-tree.md |
Any question about the manifest — and the stale-doc trap |
snapshot-testing.md |
Planning tests (§8). The snapshot tier is mandatory. |
bundle-distribution.md |
Shipping it (§7), and why git installs are a trust decision |
static-promotion.md |
Promoting a live dynamic package into a bundle |
registry-entry.md |
Making it discoverable. Do not build a hub. |
verification.md |
What the gate does and does not prove |
agent-notes.md |
Recording a non-trivial decision |
package.json, cordis.patch.yml, index.ts, provider.ts, tool.ts, tsconfig.json,
tsdown.config.ts, SKILL.md — each carries the verified contract for its artifact as comments, including
the traps that produce a bundle which builds cleanly and then fails to load.
node kit/scripts/verify-plugin.mjs <plugin-dir> # a generated bundle
node kit/scripts/verify-plugin.mjs --kit # the kit's own structure
node --test kit/tests/verify-plugin.test.mjs # prove the gate's checks can rejectIt is a static approximation and says so. It catches the mistakes that fail silently — a patch file the
gate's glob never sees, a row that matches nothing, an entry the Loader discards. It never claims a plugin
boots; only a real dsh --profile <p> --dump-config and a live tool call do that.
- Every rule in the kit cites the
dshsource that enforces it. When adshdoc and its gate disagree, the gate wins — that has already happened once, andin-tree-vs-out-of-tree.mdrecords it. - A check is not evidence until it has been observed rejecting something.
- Generated output is never hand-edited into correctness; fix the template.
- Wrap the real system. Never reimplement it. Exactly one module in a generated plugin touches the outside world; everything else is pure logic and testable without the backend.
- Render intent is part of the design.
generic/terminal/diffandlocationsare decided up front, never after the fact. - Presenters are pure functions. They run on live streaming and on session-log replay — no I/O, no session state, no clock.
A patch file whose name does not contain cordis; a missing dsh.bundle.patch; a patch not listed in
files; a comments-only patch (it throws at boot); !!js outside config/disabled; an undeclared bare
plugin name in a row; a function plugin with a default export; an impure presenter — each is rejected.
The gate is itself tested against single-field mutants, so every check has been observed rejecting something.
The pipeline is complete: 15 of 15 stages that require mechanization are mechanized, and the four that do not are judgement by design. Everything below has evidence, not assertion.
| Evidence | |
|---|---|
| The kit's gates pass, and each rejects a mutant | node --test on both suites |
A generated bundle compiles against the real @deepseek-ai/dsh-tools types |
both the scaffolded and the compiled output |
| Installation, composition, load, registration, persistence | against a real dsh, on both release lines |
| The model sees and calls the tools | a real turn listed all eight and called one |
| Presenters replay | from a tool/result a real session logged |
| The full acceptance verdict | accept → accepted, all seven stages with evidence |
| Seven target categories | scripts/golden-e2e.mjs, 7/7 |
What is not. publish — registry submission — is not this project's to manage; the entry is
format-complete and blocked on a public repository existing. And dsh itself is in developer preview and
warns that compatibility-breaking changes will land, so the version you peer on matters:
kit/guides/bundle-distribution.md.
MIT — see LICENSE. The published bundle carries the same text, and
scripts/check-shipped-copies.mjs pins the two together, so a change to
one cannot quietly leave the other asserting the old terms.


