English | 中文
A self-contained standalone repository template for an ESM Cordis plugin targeting DeepSeek Harness 0.2.1-rc.2. Every source file, compiler setting, test fixture, contributor instruction, skill, and build helper used by the repository lives below this root. A DSH host is a runtime consumer of the finished package, not a development input.
| Need | Read |
|---|---|
| Contract rules: plugin forms, manifest, dependencies, display, lifecycle, composition, client, distribution | docs/dsh-plugin-contracts.md |
| End-to-end workflow and stage routing | .agents/skills/dsh-plugin-development/SKILL.md |
| Source, test, and patch layout | src/LAYOUT.md, tests/LAYOUT.md, patches/LAYOUT.md |
| Commands, CI, and release flow | this README and .github/workflows |
.
├── .agents/skills/ # Repository-local plugin development workflow
│ ├── dsh-plugin-development/ # End-to-end coordinator
│ └── dsh-plugin-*/ # Stage skills
├── docs/
│ └── dsh-plugin-contracts.md # Authoritative package and integration contract
├── patches/
│ └── LAYOUT.md # Dependency and DSH-host patch contract
├── scripts/
│ ├── extract-patch.mjs # Host patch regeneration
│ └── patch.sh # Idempotent host patch application
├── src/
│ ├── assets/
│ │ ├── icon.svg # Plugin icon exported through `./icon`
│ │ └── locale/
│ │ ├── en.json # Display metadata
│ │ └── zh.json
│ ├── LAYOUT.md # Growth rules for source modules
│ ├── config.ts # Schemastery schema and defaults
│ ├── index.ts # Loader-facing function-plugin namespace
│ └── runtime.ts # Host boundary and activation
├── tests/
│ ├── LAYOUT.md # Test conventions
│ ├── harness.ts # Shared real-Cordis mount
│ ├── plugin.test.ts # Loader and activation tests
│ └── snapshots/
│ └── LAYOUT.md # Optional visible-output fixtures
├── .oxlintrc.json # Type-aware Oxlint configuration
├── AGENTS.md # Contributor standing orders and navigation
├── cordis.patch.yml # Profile bundle contribution
├── package.json # Exports, peers, engines, bundle metadata
├── pnpm-lock.yaml # Reproducible dependency graph
├── pnpm-workspace.yaml # Package-manager policy
├── tsconfig.json # Compiler and type-aware lint project
├── tsdown.config.ts # Source-to-runtime/declaration build
└── vitest.config.ts # Test runner configuration
docs/dsh-plugin-contracts.md owns the full contract. The orientation points are:
- A function plugin exports
name,inject,Config, andapplyas one ESM namespace and has no default export. engines.nodeis>=24.0.0;engines.dshdeclares the supported DSH range;dsh.manifestVersionanddsh.bundle.patchdescribe the public bundle layer.- Display metadata reaches Plugin Manager through the exported
./locale/*.jsonand./iconresources. This template stores their physical files undersrc/assets/and lists them infiles. @deepseek-ai/cordisand@deepseek-ai/schemasteryare host-supplied peers, duplicated indevDependenciesfor local checks. See dependencies.- A browser face declares
dsh.clientand exports its built bundle at./client.
- Replace package identity in
package.json, the Loader owner, configuration/runtime owners, focused tests, bundle metadata, TypeScript metadata, both READMEs,AGENTS.md, andsrc/assets/. - Choose the exact npm package name. It may be scoped or unscoped; do not assume the template's
@your-scope/dsh-prefix. Replace it only in identity owners, never globally inside.agents/skills/. - Set
engines.dshto the range you support. Keepengines.nodeat Node 24 LTS or newer unless a different host contract is deliberate. - Update
keywords,LICENSE,cordis.patch.yml, and the display title, description, and icon. - Add only the DSH host services the implementation uses. Apply dependencies when placing each package.
- Implement activation and host-boundary behavior in the runtime/service owners, keeping registrations fiber-owned and disposing them in tests.
- Keep every source, compiler, documentation, and project-reference path inside this repository. Do not add
link:orfile:dependencies. - Set
privatetofalseonly when the package's public dependencies and distribution artifacts are ready.
Do not add a default export to a function plugin. Cordis Loader unwraps exports.default ?? exports; a stray default export discards inject, Config, and apply.
Start with dsh-plugin-development for the complete sequence, or invoke one stage directly:
| Skill | Purpose |
|---|---|
| plan | Decide form, dependencies, configuration, compatibility, display, composition, evidence, and distribution. |
| scaffold | Instantiate and baseline-verify a new repository from this template. |
| align | Migrate an existing repository to this toolchain without changing behavior. |
| implement | Implement lifecycle-safe behavior, configuration, metadata, docs, and tests. |
| client | Add a dsh.client browser face, slots, settings forms, and ModuleLoader checks. |
| i18n | Localize browser UI with typed dictionaries and disposal evidence. |
| compose | Install the bundle into a profile and prove activation and compatibility. |
| test | Select the smallest evidence for Loader, behavior, disposal, composition, and artifacts. |
| release | Check packed, Git, or npm release readiness without publishing. |
Keep these directories when copying the template.
Run from this repository root:
pnpm install
pnpm run lint
pnpm test
pnpm run build
pnpm pack --dry-run --jsonlint is the type-aware static-analysis gate. test uses the Vitest forks pool; a restricted host that rejects child-process forks can run vitest run --pool=threads locally. build emits the ready-to-pack lib/ runtime and declarations without an install-time build.
- ci.yml: frozen install, lint, tests, and build on pushes to
mainand pull requests. - release.yml: the same checks, then packs the tarball and publishes it to the version's GitHub Release.
Install through the plugin channel:
dsh plugin --profile <profile> add <package-or-tarball>Profile startup checks engines.dsh, applies dsh.bundle.patch in bundle order, and reads display metadata without activating the plugin. See manifest and compatibility and bundle composition.
export const name = 'plugin-template'
export const inject: string[] = []
export { Config } from './config.ts'
export { apply } from './runtime.ts'
// src/config.ts
import Schema from '@deepseek-ai/schemastery'
export interface PluginConfig { /* serializable fields */ }
export const Config: Schema<PluginConfig> = Schema.object({ /* validation and defaults */ })
// src/runtime.ts
export function apply(ctx: Context, config: PluginConfig): void { /* effects */ }Config is the schema value Cordis Loader validates; PluginConfig is the public TypeScript shape. Keeping the names distinct avoids the declaration-merge false positive in no-redeclare. A service provider instead default-exports its Service subclass; do not mix the two forms.
Build before packing and inspect the archive:
pnpm run build
pnpm pack --dry-run --jsonThe archive must contain every file promised by main, types, exports, and files, plus the bundle patch and the physical display assets. See build and distribution. Git installs fetch sources; only add a self-contained prepare build when you deliberately distribute that way and document the consumer's build-script approval.
The baseline tests prove Loader-safe ESM exports and schema-resolved activation. Replace the activation assertions with observable behavior and disposal assertions for every registry contribution. Product-visible plugins also need a real Loader/profile composition test in the consuming DSH application; see tests/LAYOUT.md and evidence.