feat: add DeepSeek Harness (DSH) native plugin adapter - #792
Open
redtidev1918 wants to merge 1 commit into
Open
Conversation
redtidev1918
force-pushed
the
dsh-plugin-adapter
branch
from
September 2, 2026 03:33
94b08c5 to
c1f57c0
Compare
A self-contained DSH bundle in .dsh-plugin/: one cordis patch mounts a zero-hard-dependency Node plugin that registers the six /ponytail* slash commands and a global-layer skill provider serving .dsh-plugin/skills/. Commands steer the agent: - a DSH command handler runs without opening a model turn and its result text is rendered only in the UI (never enters model history), so each handler drives behavior with agent.steer(createUserMessage(...)), the same pattern as the built-in /plan command; it lazy-imports createUserMessage from the host (@deepseek-ai/dsh-llm, declared as a peerDependency) with a minimal-shaped fallback for dev layouts where the host package is not on the resolution path - /ponytail takes lite|full|ultra|off case-insensitively; unknown levels fall back to full instead of being echoed Skills reach every agent/preset through the skill registry global layer (the web profile disables the host skill-filesystem row; preset-local rows merge over global, so a customSkillDirs override would be inert under web): - candidates use BUNDLED_SKILL_RANK (600, lowest precedence) so a user/project skill of the same name always wins - a bundled SKILL.md with a non-kebab name or missing name/description is skipped with a warning instead of being surfaced: the host validates candidates outside the per-provider try/catch, so one bad file would otherwise take down the whole profile skill registry - an unreadable skills dir degrades to an empty provider with a warning Governance, matching the existing adapters: - tests/dsh-plugin.test.js (node:test) covers the bundle manifest, the DSH registry candidate/definition contract, that every handler steers a user message with an id, kebab-name rejection, missing-dir degradation, folded frontmatter parsing, and byte-identity of the bundled skills copies - scripts/check-versions.js guards the new package.json version - README and docs/agent-portability.md document the adapter - skills copies refreshed by scripts/sync-skills.mjs
redtidev1918
force-pushed
the
dsh-plugin-adapter
branch
from
September 2, 2026 03:43
c1f57c0 to
83e0d03
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a native DeepSeek Harness (DSH) adapter — the native-plugin tier of the existing adapters (Hermes Agent, Grok Build, Codex). DSH is a Cordis-based agent harness whose community plugin ecosystem is indexed via the
dsh-pluginGitHub topic / awesome-dsh-plugin.com; there is currently no ponytail plugin there.The adapter is a self-contained bundle in
.dsh-plugin/: onecordis.patch.ymlmounts a Node plugin (272 lines, zerodependencies, no install scripts) that/ponytail*slash commands, andWhy global-layer skills (not
customSkillDirs)The obvious approach — pointing the built-in
dsh-skill-filesystemat the bundle'sskills/via a patch config — is inert under the web profile: the hostskill-filesystemrow is disabled there because skill discovery moves to per-agent preset layers. A provider registered on the global (deployment) layer instead merges into every agent's catalog (documented indsh-web-app/cordis.patch.yml; the skills do reach a booted agent's catalog — verified end-to-end in a headless boot).Precedence is deliberately the lowest: candidates use
BUNDLED_SKILL_RANK(600 — the host's rank scale is project 100/200, custom 300, user 400/500, bundled 600), and the registry merges preset-local layers over the global layer ([global, ...chainLayers(scope)], later wins), so a user's own same-named skill wins either way.Commands steer the agent
A DSH command handler runs without opening a model turn, and its result text is rendered only in the UI — it never enters model history (
deriveEventMessageprojects onlyuser/message,assistant/message,tool/result). So each handler drives behavior withagent.steer(createUserMessage(...)), the same pattern the built-in/plancommand uses.createUserMessageis lazy-imported from the host package (@deepseek-ai/dsh-llm, declared inpeerDependencies— the conventiondsh-git-rollbackuses for host packages), with a minimal-shaped fallback message for dev/link layouts where the host package is not on the module-resolution path./ponytailtakeslite|full|ultra|offcase-insensitively; unknown levels fall back tofullinstead of being echoed into the prompt.Robustness
SKILL.mdwith a non-kebab name or missingname/descriptionis skipped with a warning rather than surfaced: the host validates candidates outside the per-provider try/catch, so one bad file would otherwise take down the whole profile's skill registry..gitattributes, so a Windows checkout (core.autocrlf) storesSKILL.mdwith\r\nand npm packs whatever is on disk — without normalization all six skills would silently disappear on such machines.ponytail:comment.Security surface
Runtime plugin: zero
dependencies, no install scripts, noeval, network, child-process, or file writes; it reads only files inside the package's ownskills/directory (paths are built fromreaddirDirent.name, no traversal). Two independent adversarial audits with fresh contexts, treating the plugin as third-party code on user machines: the first returned FIX-FIRST (commands were inert — the issue this PR's design section addresses — plus missing kebab-name validation and/offedge cases); after fixes, a re-audit returned SHIP. Post-audit hardening (CRLF handling, explicitnode:cryptoimport, definition freezing, docs alignment) was reviewed manually against host source — the third-party audit tool was unavailable for that final pass, so I state plainly it was a manual review, not a fresh audit.Governance (matches the existing adapters)
tests/dsh-plugin.test.js(node:test, picked up by the rootnpm testglob) — 9 tests covering: bundle manifest +dsh.bundledeclaration; the DSH registry candidate/definition contract; that every command handler steers a user message with an id (the one field the host inbox enforces);/offand case/unknown-level handling; kebab-name rejection; CRLF parsing; missing-dir degradation; folded-block frontmatter; and byte-identity of the bundledskills/copies.scripts/check-versions.jsnow guards.dsh-plugin/package.json(all version files pinned to the same version).README.md+docs/agent-portability.mddocument the adapter..dsh-plugin/skills/copies are refreshed by.dsh-plugin/scripts/sync-skills.mjs(byte-checked by the test).Verification
node --test tests/dsh-plugin.test.js→ 9/9 pass.pip install pandas). Without pandas locally it is 92/93: the one failure (csv: correct pandas one-liner) also reproduces on a clean tree without our changes — purely the missing pandas, verified by re-running the suite with pandas present.node scripts/check-versions.js→ all 9 version files pinned at 4.9.0.npm pack --dry-run→ 11 files, ~14 kB, lib + skills + patch + manifests only./planpattern.Install
Happy to adjust naming, wiring, or anything else to fit your conventions. I deliberately did not publish the
dsh-plugin-ponytailnpm name (verified free on the registry) — it stays available for you to publish as the first-party package.