跪拜 Guibai
← Back to the summary

DeepSeek Harness Turns LLMs Into an Execution Layer With User-Written Plugins

DeepSeek Harness Plugin Development in Practice: From Minimal Plugin to Automated Daily Report

Introduction

DeepSeek's open-source Harness (codenamed "Black Whale") is not a new model, but an "execution layer" wrapped around large models. The core slogan is "Everything is a plugin" — models, tools, interfaces, and session records are all assembled from plugins. This article dissects Harness's plugin mechanism (the Cordis framework) from a technical perspective, providing a complete workflow from environment setup, minimal plugin writing, and configuration mounting to automation practice, along with an objective assessment of the current version's boundaries and security considerations.

Problem Definition: The Gap from "Chat" to "Execution"

Most users only stay at the conversation level after getting Harness, like "buying a CNC machine and using it as a hammer to drive nails every day." The real way to unlock its value is to write plugins and outsource repetitive labor to AI. Harness has only been released for a week, and community plugins under the dsh-plugin tag on GitHub have already exceeded 900.

Black Whale

Architecture Analysis: The Cordis Plugin Framework

Harness's underlying layer uses the Cordis plugin framework. The core idea: all capabilities are "plugins," and a plugin is essentially a TypeScript file that exports a fixed structure. The official 195 packages (command execution, session recording, etc.) are all composed of plugins, and user plugins have exactly the same status as official plugins.

Everything is a Plugin

Environment Setup

Minimal Plugin Implementation

A minimal plugin that registers a hello_world tool:

// my-plugin.ts
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'my-plugin'
export const inject = ['tools']
export function apply(ctx) {
  ctx.tools.register(defineTool({
    name: 'hello_world',
    description: 'Greet someone, used to verify if the plugin loaded successfully',
    parameters: {
      who: { type: 'string', required: true, description: 'The person to greet' }
    },
    output: {
      schema: { type: 'object', additionalProperties: false, properties: { message: { type: 'string', required: true } } },
      render: (_args, value) => [{ type: 'text', text: value.message }]
    },
    async execute(args) {
      return { message: `Hello, ${args.who}, plugin loaded successfully` }
    }
  }))
}

Minimal Plugin

Pitfalls Encountered

  1. Must use named exports: export default causes the injection declaration to be silently discarded. The plugin appears to load but does not take effect, and no error is reported.
  2. Schema constraints: The schema for object-type outputs must declare additionalProperties: false, otherwise registration fails.
  3. Injection order: inject: ['tools'] means wait for the tool registry to be ready before executing.

Configuration Mounting

Create a cordis.yml to declare plugin mounting information:

- insert:
  - id: my-plugin
    name: '/absolute/path/to/your/directory/my-plugin.ts'

Note: The path must be an absolute path (Cordis does not support relative paths). Start with the patch:

pnpm dsh web --patch ./cordis.yml

Trigger "use hello_world to greet Xiaohu" in the conversation, and receiving "Hello, Xiaohu, plugin loaded successfully" confirms success.

Practice: Automatically Generate Daily Report Drafts

Pain point: Writing a daily report before leaving work every day and summarizing five daily reports into a weekly report every Friday is repetitive, mechanical, and easy to miss.

Daily Report Plugin

import { defineTool } from '@deepseek-ai/dsh-tools'
import { readFileSync, writeFileSync, existsSync } from 'fs'
export const name = 'daily-draft'
export const inject = ['tools']
export function apply(ctx) {
  ctx.tools.register(defineTool({
    name: 'gen_daily_draft',
    description: 'Read yesterday\'s to-do list and generate today\'s daily report draft according to a template',
    parameters: {
      workspace: { type: 'string', required: true, description: 'Absolute path to the workspace directory' }
    },
    output: { schema: { type: 'object', additionalProperties: false, properties: { path: { type: 'string', required: true } } },
      render: (_a, v) => [{ type: 'text', text: `Draft generated, ${v.path}` }] },
    async execute(args) {
      const todoPath = `${args.workspace}/todo.md`
      const draft = existsSync(todoPath)
        ? `【Draft Pending Confirmation】\nYesterday\'s to-dos:\n${readFileSync(todoPath, 'utf-8')}\n(Please fill in after verifying the actual progress of the day)`
        : '【Draft Pending Confirmation】No yesterday to-do record found today, please supplement.'
      const out = `${args.workspace}/daily-$(date +%F).md`
      writeFileSync(out, draft)
      return { path: out }
    }
  }))
}

Design Points: Only generates a draft and clearly marks it as "pending confirmation," never fabricating content that did not happen for the user — mitigating AI hallucination risks through rule constraints.

Packaging and Publishing

Using absolute paths locally is fine, but publishing to the community requires declaring in package.json:

{
  "name": "dsh-daily-draft",
  "type": "module",
  "main": "my-plugin.ts",
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}

Install command: dsh plugin --profile web add github:account/repo

Vibe Coding Tip: The DSH plugin structure (single file + apply entry + YAML) is naturally suited for AI generation. The specification can be submitted to tools like Cursor to generate complete source files in seconds.

Boundaries and Security

Dimension Description
Version Stability Current 0.1.0 pre-release version. Officials have explicitly stated interfaces will still be adjusted. Recommended for experimentation, not production deployment.
Security Risk Plugins are essentially code running on the local machine. Installing plugins from unknown sources is equivalent to handing over system permissions. Only install official or highly-starred plugins.
Technical Barrier Requires some TypeScript foundation, but the learning curve is gentler compared to a full programming language.

Summary

DeepSeek has opened the door to the "execution layer" through Harness. Core viewpoint: True automation is not about learning all the tools, but about only needing to say one sentence, and the tools string themselves together to work. Next step direction: Chain the daily report plugin to a weekly report plugin to achieve automatic Friday summaries.

Written at the End