tamashi486/dsh-openspec

dsh-openspec

把 OpenSpec(规范驱动开发)接入 DeepSeek Harness:内置六个 agent skill,并从插件自身依赖解析 openspec CLI,无需全局安装、无需按项目拷贝 .agents/skills | OpenSpec (spec-driven development) for DeepSeek Harness: six bundled agent skills + CLI resolution from the plugin dependency. No global install.

Uncategorizedagent-skillsai-coding-agentdeepseek-harness

dsh-openspec

English | 中文

OpenSpec — the spec-driven development workflow (explore → propose → apply → archive) — as a DeepSeek Harness plugin: six openspec-* skills in the skill catalog, plus the openspec CLI resolvable from the agent's shell. No global install, no per-project .agents/skills copy, and the skills work even outside a git repository.

What you get

Six vendored skills, routed by their descriptions, so plain language triggers them:

SkillWhat it does
openspec-exploreThinking partner: explore ideas, investigate problems, clarify requirements — before or during a change
openspec-proposeCreate a change and all its planning artifacts (proposal, spec deltas, design, tasks) in one step
openspec-apply-changeImplement the tasks of a change
openspec-update-changeRevise an existing change's planning artifacts (never touches code)
openspec-sync-specsFold a change's delta specs into the main specs, without archiving
openspec-archive-changeFinalize and archive a completed change

Plus the CLI wiring. The plugin carries @fission-ai/openspec as its own dependency and, at profile load, installs a small openspec launcher into a directory that is already on your PATH — so the bare openspec command every skill calls actually resolves:

#!/bin/sh
exec "/abs/path/to/node" "/abs/path/to/node_modules/@fission-ai/openspec/bin/openspec.js" "$@"

Candidate directories are only ones already on PATH, preferring the Node installation's bin dir, npm's global prefix, ~/.local/bin, and the Homebrew/system prefixes. An openspec the plugin did not write is never touched.

Install

dsh plugin add /path/to/dsh-openspec

Restart the profile (or let patchReload: live pick it up). On load the plugin:

  1. mounts the six skills as a bundled provider — visible from every workspace, git or not;
  2. probes the CLI dependency and, if openspec is not yet on PATH, installs the launcher (logged; remove anytime with /openspec uninstall-shim).

Verify with /openspec doctor.

Quick start

Initialize a project once — from the project's own shell:

openspec init --tools agents     # scaffolds openspec/ and the project config

Or just ask in a conversation: the skills detect a missing OpenSpec root and offer to run openspec init for you (/openspec init <absolute-path> works too).

Then drive the workflow in plain language:

  • "help me think through how to add dark mode" → openspec-explore
  • "propose add-dark-mode" → openspec-propose
  • "apply the change" → openspec-apply-change
  • "archive it" → openspec-archive-change

Note the planning boundary (upstream's design): propose stops when the artifacts are ready. Implementation starts only when you explicitly ask to apply.

The /openspec command

CommandPurpose
/openspec doctorOne-screen diagnosis: skill count, CLI version and entry, and what a shell actually resolves openspec to
/openspec shim(Re)install the openspec launcher onto PATH
/openspec uninstall-shimRemove the launcher (only if this plugin wrote it)
/openspec init <absolute-path>Run openspec init --tools agents in a project directory. An absolute path is required, not merely advised: a relative one would resolve against the profile server's cwd, and the command rejects it rather than initializing the wrong tree

Troubleshooting

Run /openspec doctor and match what it says:

DiagnosisMeaning / fix
CLI package : MISSINGThe CLI dependency didn't install. Re-run dsh plugin add for this plugin (or dsh plugin add @fission-ai/openspec), then /openspec shim.
PATH resolves : absentNothing on PATH provides openspec, so the skills' bare command won't resolve. Fix: /openspec shim.
PATH resolves : foreign (<path>)Someone else's openspec is what actually runs, so the command resolves fine and this is not a fault. The skills call that binary; if its version drifts from the vendored skills, put the plugin's launcher in an earlier PATH directory.
launcher shadowedThe launcher was written but an earlier PATH entry still wins. Move its directory ahead on PATH, or remove the other install.
launcher could not be installed (no-writable-path-dir)No directory on your PATH is writable. Add one (e.g. ~/.local/bin), reload the profile, and retry — or install OpenSpec globally yourself.

Precedence note: after openspec init inside a git repository, DSH also discovers the project's own .agents/skills copies, which outrank the bundled ones — same content, no action needed. Outside git repositories only the bundled copies are visible, which is exactly the case this plugin exists for.

Why a plugin instead of the plain install

OpenSpec's own installer assumes two things that do not hold inside DSH. Both are verified against the current sources, not assumed:

1. Project-level skills are invisible outside a git repository. openspec init writes skills to <project>/.agents/skills/. DSH discovers project skills via findProjectRoot in dsh-skill-filesystem, which probes for a .git entry and nothing else:

if (await pathExists(join(current, '.git'), fs)) return current;

In a non-git directory the generated skills exist on disk but are never seen. This plugin mounts them through bundledSkillDir instead, which is independent of project-root detection.

2. The bare openspec command is not on the agent's PATH. Every vendored skill body calls openspec …. The profile's own node_modules/.bin is not on the PATH the bash tool sees, and ctx.shellEnv injects only DSH_*-prefixed keys — so a declared dependency alone leaves the command unresolved. Hence the launcher described above, which never clobbers an openspec it did not write.

Two consequences fall out of this arrangement:

  • No contested directory. .agents/skills/ is shared with Codex and Zed Agent, which rewrite each other's trees there. This plugin never writes to it.
  • One copy, upgraded in one place. dsh plugin update refreshes the skills for every project at once, instead of openspec update per repository.

What is deliberately not taken over: openspec/ stays in your project and stays in git. The plugin distributes capability; it does not own your specs.

Maintaining

src/ is the source of truth; lib/ is the compiled output and is committed — dsh plugin add loads the package as-is, and pnpm blocks a git-hosted plugin's prepare script by default, so a build step at install time would force every consumer to edit allowBuilds first.

npm ci
npm run typecheck    # src/ + scripts/ (includes the contract test)
npm run build        # src/ -> lib/ (+ lib/types/)

CI fails if lib/ is stale relative to src/, so always commit the rebuild.

Vendoring the skills. The skills under skills/ are generated: upstream renders them per tool at install time and ships no skills tree in its npm package. scripts/vendor-skills.ts therefore runs upstream's own installer in a throwaway git repo (--tools agents — the vendor-neutral, skills-only target, which generates no opsx-* command files and renders cross-references as skill names, matching how DSH addresses its catalog) and copies the result:

npm run vendor-skills                              # latest published version
npm run vendor-skills -- --version 1.13.0

Then align dependencies["@fission-ai/openspec"] in package.json with the version the script prints. skills/VENDORED.md records the provenance.

Checking the wiring. scripts/checks/plugin-contract.ts is a compile-time contract test: npm run typecheck fails if the plugin stops satisfying cordis's plugin shape or dsh-commands' CommandDefinition. For the full integration check (requires the plugin installed into a profile):

dsh plugin --profile opstest add "$PWD"
npm run check-load -- --profile opstest --require propose,apply-change

It boots the profile through dsh's real runProfile path and asserts the skills are visible from a workspace with no .git — the case the plain install fails.

Layout

PathRole
src/index.tsPlugin source: CLI resolution, PATH launcher, /openspec command
lib/Compiled output (committed; what dsh loads)
cordis.patch.ymlRegisters the bundled skill provider
skills/Vendored openspec-*/SKILL.md (generated; see skills/VENDORED.md)
scripts/vendor-skills.tsRe-vendor skills/ from upstream (run via tsx)
scripts/check-load.tsLoad-time integration check (run via tsx)
scripts/checks/plugin-contract.tsCompile-time contract test for the cordis seam
.github/workflows/ci.ymlCI: typecheck and build, a stale-lib/ check, and a real boot assertion from a non-git workspace

Licence

MIT. OpenSpec itself is MIT-licensed and is consumed here as an unmodified dependency; the vendored skill text under skills/ is generated from it.