feat: add DeepSeek Harness (dsh) support - #2144
Conversation
DeepSeek Harness ships a skill registry and a native `skill` tool, but `dsh plugin add github:obra/superpowers` failed with "declares no dsh.bundle": the repo had no profile-layer declaration, so nothing registered the skills and nothing injected the `using-superpowers` bootstrap. Skills that a session never hears about never trigger. The plugin is a Cordis module that injects `skills` and `systemPrompt`: it registers this repo's own `skills/` through `ctx.skills.register()` and contributes the bootstrap as an order-50 system-prompt section. dsh reassembles the system prompt before every model step, so the bootstrap loads on the first request and survives compaction with no dedup guard and no per-session opt-in. Node builtins only — a plugin resolved from a profile cannot see the `@deepseek-ai/*` packages nested in the dsh installation, so both registries are reached through the injected context alone. No skill bodies change: dsh exposes a native tool for every action the skills name, so the port needs no tool mapping.
arittr
left a comment
There was a problem hiding this comment.
Thanks for doing this properly — the dsh plugin install path is exactly what was asked for when #1586 closed, and the before/after eval + install-pack test are the strongest parts. Two observations, one substantive and one minor.
1. The "no tool mapping needed" claim only covers the brainstorming path
The PR argues a dsh-tools.md reference is unnecessary because "dsh exposes a native tool for every action named by the skills." That's true for the actions your acceptance transcript exercises, but not for subagent dispatch, which the porting guide's tool-mapping step specifically calls out ("dispatch a subagent, including how to pass the agent type").
dispatching-parallel-agents, subagent-driven-development, and the code-review skills name specific subagent types (Explore, Plan, reviewer archetypes, etc.). dsh's subagent/subagent_fork tools have no subagent-type parameter — the role and instructions must be written into the prompt itself, and a plain subagent sees none of the parent conversation, so skills that expect a typed dispatch need that translation spelled out somewhere. Nothing in the injected bootstrap or the skill bodies provides it, and no run in the PR (or that I've seen) exercises any typed-subagent skill on dsh.
Suggest adding either a short mapping block appended inside the injected section, or a skills/using-superpowers/references/dsh-tools.md linked from the Platform Adaptation list (pi maintains both places; either alone satisfies the guide). It only needs to cover the deltas: subagent dispatch (no named types → prompt preamble; subagent_fork for inheriting context), todo_write whole-list replacement, plan mode via exit_plan_mode, and that dsh's skill catalog renders plain names (brainstorming), never the superpowers:-prefixed forms used in skill prose. It's not load-bearing for brainstorming — your transcript proves that — but it is the difference between "the process skills work" and "every skill works," and the guide's definition of done asks for it.
2. Minor: the precedence sentence in docs/README.dsh.md is surface-dependent as written
Superpowers skills are registered as
bundled, so a skill of the same name in any of those roots wins.
Two inaccuracies, checked against dsh's skill registry source (rc.6):
ctx.skills.register()registers runtime entries (rank 250), not bundled entries (rank 600) —source: 'bundled'is display metadata and doesn't change the rank.- Within one registry layer, lower rank wins: project roots (100/200) > runtime (250) > user roots (400/500) > bundled (600). In the presetless headless profile (the one you tested), the filesystem provider and this plugin share the global layer, so a project skill of the same name wins over Superpowers but a user-root skill loses. In preset-based profiles the layering changes it again (preset-layer entries win a duplicate outright). So "any of those roots wins" is wrong for at least one supported surface; worth a one-line correction (or just deleting the sentence).
Neither point blocks the approach — the mechanism is right and the acceptance run is real. Happy to follow up with a concrete mapping-file draft if useful.
dsh has no named subagent types, so skills that dispatch typed subagents need the translation spelled out. Inline the dsh deltas in the bootstrap section and ship the full mapping as references/dsh-tools.md, linked from the Platform Adaptation list. Tests assert both copies stay in sync.
Skills registered via ctx.skills.register() are runtime entries (rank 250), not bundled entries (600), and precedence over local roots depends on the profile shape rather than 'any of those roots wins'.
|
Pushed two follow-up commits to this branch (maintainer edits) covering the mapping gap and the precedence note:
Full suite still green: |
|
Hi! I'm filing a separate, narrower ask-PR at #2154 — same routing, smaller diff. No coordination beyond this comment. The difference is mainly: #2154 ships the manifest, the runtime doc, a compat matrix, and a manifest test — no I haven't talked to you about this directly because coordination between the two PRs belongs in the PR threads where maintainers can see it. If maintainers prefer your fuller shape (with the Either way — the eval evidence you collected (especially the clean-session transcript with Two small things I can offer to your PR if useful (separate commits, not cross-mingled):
Let me know if either would be welcome; I won't push them uninvited. — JFWaskin |
|
Sharing an empirical observation from testing a dsh-based Superpowers integration, in case it's useful for the acceptance guidance on this runtime. Model tested: What worked:
What it did NOT do (the gap):
So with this model, the bootstrap is understood but the actual skill-tool invocation is skipped - it follows the instructions textually rather than triggering the skill via the tool. Worth noting this is |
Who is submitting this PR? (required)
deepseek-v4-flashdsh0.1.0-rc.6 for every dsh claim below@deepseek-ai/dsh-base,@deepseek-ai/dsh-headless, andsuperpowers(this branch) — nothing else. Authoring environment: Cursor's stock toolset plus local MCP servers, none of which touch this repo.This adaptation was prepared with AI assistance; I verified the installation, the acceptance run, and every claim below locally on macOS.
What problem are you trying to solve?
I use DeepSeek Harness (
dsh) daily. The README does not cover it. The expected install command exits 0, but installs the repo as a plain dependency instead of a profile layer:dsh already has a skill registry and a native
skilltool. Without skill registration and theusing-superpowersbootstrap, a dsh session does not know Superpowers is installed. Against unmodifieddev, the acceptance prompt scaffolded and built a Vite app without asking a question. The baseline transcript is under Evaluation.What does this PR change?
This PR adds a dsh plugin (
.dsh/plugins/superpowers.js), the bundle patch and root-package.jsonfield required fordsh plugin addto recognize this repo as a profile layer, install docs, and tests. The plugin registers this repo'sskills/throughctx.skills.register()and adds theusing-superpowersbootstrap as an order-50 system-prompt section.Is this change appropriate for the core library?
Yes. The contributor rules allow new harness support. This implementation uses only Node builtins, adds zero runtime dependencies, and writes nothing outside the installed profile. It does not modify
skills/: no skill body,references/file, or Platform Adaptation entry changes. dsh exposes a native tool for every action named by the skills, so I tested whether correct operation required adsh-tools.md. It does not, and the acceptance run passes without one. This matches #1847 and the resolution of #1995.What alternatives did you consider?
ctx.systemPrompt.context(), a durable user-role snapshot. I chose.section()for the reasons below and can switch if requested.dsh-superpowerson npm) before writing this. It is not the install path here because routing dsh users through my repo would keep them from receiving your updates. This PR installs fromobra/superpowersand nothing else. I will archive the standalone package if this lands.dsh.bundleonly from the installedpackage.json, so it cannot discover any existing manifest in the repo..jsas-is, so no transpilation or dev dependency is required.The one deliberate deviation from the guide
docs/porting-to-a-new-harness.mdPart 5 says Shape B injects the bootstrap as a user message. It cites #750 (tokens grow when a system message repeats every turn) and #894 (multiple system messages break some models). I use a system-prompt section for dsh because:injectBootstrapflag, or re-injection after compaction.ctx.systemPrompt.context()) is for dynamic runtime context. TheincludeRuntimeContextconfig gates it, and any plugin can switch it off withsuppressRuntimeContext(). A bootstrap required in every session should not depend on that switch.This differs from an explicit instruction in the guide. If maintainers prefer
context(), I will move it and add the required deduplication and post-compaction handling.Does this PR contain multiple unrelated changes?
No. The change covers one harness. Every touched file is required by the porting guide: entry point, manifest field, install docs, README, the Codex sync exclude for the new dotdir (Part 6), and tests.
Existing PRs
I have reviewed all open AND closed PRs for duplicates or prior art
Related PRs: none for this harness. I searched open and closed issues and PRs for
dsh,deepseek, anddeepseek-harness.deepseek-ai/deepseek-harness, DeepSeek's own harness. feat: add DeepSeek TUI harness support #1586 was closed for not using the harness's plugin install, targetingmain, and turning theAGENTS.mdsymlink into a file. None of those issues applies here.Environment tested
dsh)deepseek-v4-flash(provideropencode-go)I tested only macOS 26.5.2 (arm64) and the model listed above. dsh is a developer preview, so every version is pinned. I have not tested Linux or Windows, and dsh's plugin surface may still move.
New harness support (required if this PR adds a new harness)
I installed this PR's branch with dsh's own command into a fresh profile (
spdshacc). The working directory was empty.DSH_AGENTS_HOMEpointed at an empty directory, so the catalog contained only the 14 bundled skills and nothing personal.dsh pluginadded the layer by itself, off thedsh.bundledeclaration in the installed manifest.Result: PASS. The first action of the session was
skill("brainstorming")— before any exploration, any shell command, and any file write. The directory was still empty when the turn ended.Smoke check — "What are your superpowers?"
Clean-session transcript for "Let's make a react todo list"
--- SYSTEM PROMPT ACTUALLY SENT (verbatim, from the session log's
request/header) ---This is the recorded request, not an assertion about it. The plugin's section is
the
<EXTREMELY_IMPORTANT>block, contributed at order 50 — after dsh's persona(order 0), before its tool guidance (100-199). Truncated after the block; what
follows is dsh's own stock tool guidance.
--- TOOLS OFFERED IN THAT REQUEST ---
--- SKILL CATALOG IN THAT SESSION (user-role
<system-reminder>from dsh's skill registry) ------ CONVERSATION ---
The session ends there: dsh's headless surface answers one task and exits, and brainstorming's next move is a question for the human partner.
Evaluation
dsh plugin add github:…. The latter run is transcribed above. I also ran two smoke checks. All four loaded the bootstrap; both acceptance runs calledskill("brainstorming")as the session's first action and wrote nothing.devfor the baseline. The profile shape, model, prompt, and empty directory matched the passing run; the only difference was this PR. Baseline: 27 tool calls, 0 of themskill, 8writes, and a built Vite app before any question reached me. With the plugin:skill("brainstorming")first, 1 read-onlyls, 0 files. A later repeat of both runs gave 17 calls / 9 writes for the baseline and 3 calls / 0 writes with the plugin — the counts move between runs, and on that repeat the baseline did ask a question, but only after it had finished building. What is stable across runs is the ordering: without the plugin the first action isbash, with it the first action isskill("brainstorming").Baseline on unmodified
devThe profile manifest confirms it never became a layer:
From that session's log: system prompt 4029 chars with no
EXTREMELY_IMPORTANTblock (7162 chars with it, in the passing run), and the tool sequence was~/.agents/skillspresent, the session catalog is dominated by personal skills and the smoke answer gets vague. The bootstrap still loads and brainstorming still triggers, but I isolatedDSH_AGENTS_HOMEfor the transcript so the evidence is about this PR and not about my machine.bash tests/dsh/run-tests.sh— 10 unit tests against a faked Cordis context (registration, bootstrap section name/order/content, no cross-apply state, malformed-skill skipping, missing bootstrap, missing skills dir) plus an install check that packs the repo and asserts the packed tree alone satisfies the bundle declaration with no runtime dependencies.tests/pi/,tests/codex-plugin-sync/, andscripts/lint-shell.shstill pass.Rigor
superpowers:writing-skillsand completed adversarial pressure testing (paste results below) — N/A: this PR does not touchskills/at all.skills/directory, a missingusing-superpowers, skills with no frontmatter / no description / an empty body, and repeatedapply(); the install test proves the packed tree, not the working tree.Human review