Introduction

The philosophy of DeepSeek Harness (hereinafter referred to as DSH) is “Everything is a plugin”: Tools, Configs, Services, Events, and middleware must ultimately be integrated as plugins. For those new to plugin development, the difficulty usually isn’t a lack of documentation, but a lack of a minimal example that connects the concepts, runs within a profile, and provides observable output at every step.

Below is an introduction to dsh-plugin-practice. It breaks down the core concepts of plugin development into six progressive lessons. The code accumulates lesson by lesson and is itself a standard DSH Bundle, which can be installed and uninstalled using official commands.

What is this

dsh-plugin-practice is maintained by Ri0n72Y and is positioned as a minimal practice repository for learning DeepSeek Harness / Cordis plugin development, version 0.1.0. It is a TypeScript package built from src/ to lib/ using tsdown via the prepare script.

The specific problem it solves is: every concept is implemented as runnable code, providing a complete command chain from building, installing, starting to verification; each lesson has corresponding Agent test statements and expected output, allowing for self-verification after learning.

The repository contains two patch files corresponding to two loading methods: cordis.patch.yml for official Bundles; cordis.dev.patch.yml for overlay mode to load local TypeScript source code directly.

Course Content

The current content covers six lessons:

Lesson File Core Concept
1 src/plugin.ts apply(ctx), ctx.effect(), disposer, plugin lifecycle
2 src/workspace-info.ts inject = ['tools'], defineTool(), arguments and canonical output
3 src/configurable-greet.ts Config interface, Schemastery, defaults, runtime configuration validation
4 src/workspace-name-service.ts + src/workspace-name-tool.ts Service Provider, Context declaration merging, Consumer / inject
5 src/workspace-event-* typed Events, ctx.emit(), ctx.on(), loosely coupled broadcast
6 src/workspace-transform-* ctx.waterfall(), next(), around middleware, short-circuit

A few notes:

  • Lesson 1’s plugin outputs [practice-lifecycle] heartbeat every 5 seconds at runtime, and outputs disposed upon uninstallation, used to observe the timing of side effects registered by ctx.effect() and the cleanup of the disposer.
  • Lesson 3’s configured_greet tool uses greeting: Hi from the Bundle patch, corresponding to Config defaults and runtime configuration validation.
  • Lesson 4 uses Context declaration merging to customize the ctx.workspaceName Service. The Provider and Consumer belong to two separate files.
  • Lesson 6 simultaneously demonstrates the wrapping of around middleware and the short-circuiting of block middleware: input hello returns HELLO after being uppercased; input blocked words short-circuits the default handling in the block middleware, ultimately resulting in ** BLOCKED **.

Environment Requirements

  1. Node.js ^22.19.0 || >=24.0.0;
  2. pnpm (repository declares pnpm@11.7.0);
  3. dsh CLI installed and executable locally.

First run the following command to confirm the CLI is available, then proceed with the subsequent steps:

dsh --help

Local Development and One-Click Deployment

Clone the repository and install dependencies:

git clone https://github.com/Ri0n72Y/dsh-plugin-practice.git
cd dsh-plugin-practice
pnpm install

After finishing daily development, execute:

pnpm deploy

deploy is defined in package.json as:

{
  "scripts": {
    "deploy": "pnpm run prepare && dsh plugin --profile practice add ."
  }
}

That is, first build lib/ from src/ using tsdown, then install or update the current checkout into the practice profile. Then start DSH:

dsh --profile practice

If you want to check the final combined configuration first:

dsh --profile practice --dump-config

The default development profile is fixed to practice. Change the name directly by adjusting the deploy script in package.json.

Installing with Official Commands

pnpm deploy merely connects the build and official installation commands; plugin installation and profile management are still handled by DSH. You can also skip the local steps and install the Git repository directly:

dsh plugin --profile practice add github:Ri0n72Y/dsh-plugin-practice

This repository is a TypeScript package, and package.json provides a prepare script, so lib/ will be built from src/ automatically after installing via Git. Note that for pnpm 10+, when installing Git dependencies for the first time, you may need to authorize build scripts in the profile’s pnpm-workspace.yaml via allowBuilds.

It can be installed this way because package.json declares the Bundle manifest according to official conventions:

{
  "dsh": {
    "bundle": {
      "patch": "./cordis.patch.yml"
    }
  }
}

The installation chain is: dsh plugin add reads dsh.bundle pointing to cordis.patch.yml, and the patch then loads the built lib/*.js via package export paths.

Source Development / Overlay Mode

If you don’t want to build every time you modify the source code, you can use overlay mode to load .ts files directly. First, replace /ABSOLUTE/PATH/TO/dsh-plugin-practice in cordis.dev.patch.yml with the repository’s actual absolute path, then run:

dsh web --patch /ABSOLUTE/PATH/TO/dsh-plugin-practice/cordis.dev.patch.yml

If running the CLI from the DeepSeek Harness source repository, use:

pnpm dsh web --patch /ABSOLUTE/PATH/TO/dsh-plugin-practice/cordis.dev.patch.yml

Testing After Installation

After deploying and starting through the steps above, test the Agent line by line:

Use the workspace_info tool and tell me the current workspace.
Use configured_greet to greet Ada.
Use workspace_name and return only the workspace name.
Use announce_workspace to announce the current workspace.
Use waterfall_demo with input "hello".
Use waterfall_demo with input "blocked words".

Expected behavior:

  • workspace_info returns the current DSH Node process’s cwd and directory name.
  • configured_greet uses greeting: Hi from the patch, e.g., returns Hi, Ada!.
  • workspace_name gets the directory name via the customized ctx.workspaceName Service.
  • announce_workspace emits the practice/workspace-announced event, and the listening plugin outputs [workspace-event] announced: <name> in the terminal.
  • waterfall_demo("hello") returns HELLO; waterfall_demo("blocked words") returns ** BLOCKED **.
  • In the background, [practice-lifecycle] heartbeat is output every 5 seconds, and disposed is output upon uninstallation.

The runtime behaviors corresponding to the six lessons can all be observed directly.

Uninstallation and Common Commands

Uninstall the plugin:

dsh plugin --profile practice remove dsh-plugin-practice

Common development commands:

pnpm run typecheck
pnpm run build
pnpm run check
pnpm deploy

dsh --profile practice --dump-config
dsh --profile practice

Applicable Scenarios and Notes

Suitable for developers who want to get started with DSH / Cordis plugin development, especially those who wish to go through the concepts in the order of lifecycle → Tool → Config → Service → Event → middleware. The repository is small in size, with main dependencies being @deepseek-ai/cordis ^4.0.1@deepseek-ai/dsh-tools ^0.1.0-rc.5@deepseek-ai/schemastery ^3.18.1, making it suitable for reading the source code directly.

Notes before use:

  1. Plugins run with the permissions of the current dsh process. You should check the source code before installing any third-party plugins; the license for this repository is not explicitly declared in the collected materials (the LICENSE file is listed in the files of package.json), and the actual content of the repository shall prevail.
  2. DSH is still in a rapid iteration stage; if there are breaking changes to the API, you should refer to the official development documentation and the current TypeScript interfaces for adjustment, and do not assume the repository code will always be usable.
  3. The commands in this article use the practice profile uniformly; if there is a conflict with existing profiles or isolation is required, adjust the corresponding deploy script and the --profile parameter in the installation command.

Conclusion

The value of dsh-plugin-practice lies in “runnability”: every concept corresponds to a piece of source code, a test statement, and an expected output, forming a closed learning loop. If you are looking for your first hands-on project for DSH plugin development, you can start here.

  • Community Directory Page (independent site, no official affiliation with DeepSeek / Fang Fang): https://www.skillhub.cn/plugins/Ri0n72Y/dsh-plugin-practice
  • GitHub Repository: https://github.com/Ri0n72Y/dsh-plugin-practice