Introduction

The DeepSeek Harness ecosystem is plugin-centric. When developing plugins, developers often need to handle settings page form rendering, storage logic, route registration, and security validation themselves. Reinventing the wheel is not only time-consuming but can also introduce security vulnerabilities. dsh-config-form provides a unified settings page container; plugins only need to declare fields to obtain a rendered form and routes.

Plugin Overview

This is a router and renderer, not a framework. It provides a unified settings entry point for all DeepSeek Harness plugins that actively integrate with it. The maintainer is begonia599. Through declarative configuration, plugins can quickly obtain a complete settings form while sharing routing and security check mechanisms.

Core Features

  • Declarative field routing and rendering: Plugins define the form structure through declarations, and this plugin handles routing and rendering.
  • Shared routing and security checks: Provides a unified HTTP route and entry point, centralizing security validation.
  • Secret isolation: Sensitive information (such as tokens) is accessed via ctx.credentials and does not appear in the settings document.
  • Layered parsing and version fencing: Supports layered resolution of configuration values and prevents concurrent write conflicts with version fencing.
  • HTTP API support: Provides HTTP interfaces for listing, details, writing, and secret management.

Installation and Setup

Use the official installation command to complete the installation:

dsh plugin --profile web add dsh-config-form

Typical Usage

Plugin developers need to introduce the configForm dependency and declare the field structure. The standard usage workflow is as follows:

  1. Declare fields: Call ctx.configForm.declare in the plugin code to define configuration items.
  2. Get configuration: Use cfg.get() to retrieve the resolved configuration values.
  3. Watch changes: Use cfg.watch to listen for user save operations and execute follow-up logic.
  4. Handle secrets: Use await cfg.secret('token') to securely obtain sensitive credentials.

Code example:

export const inject = ['configForm']

export function apply(ctx: Context) {
  const cfg = ctx.configForm.declare<Settings>(ctx, {
    id: 'my-plugin',
    title: { zh: '插件标题', en: 'Plugin Title' },
    groups: [
      {
        title: { zh: '常规', en: 'General' },
        fields: [
          { kind: 'text', key: 'settingKey', label: { zh: '设置项', en: 'Setting' }, default: 'value' }
        ]
      }
    ]
  })

  // 读取配置
  cfg.get().settingKey

  // 监听变更
  cfg.watch(next => {
    // 配置已保存
  })

  // 安全获取密钥
  await cfg.secret('token')
}

Applicable Scenarios and Notes

  • Positioning: It is a router and renderer, not a framework.
  • Storage: The plugin author chooses the storage logic. A store object can be passed, or the settings seam can be relied on for automatic saving.
  • Security restrictions: Secrets do not appear in the settings document. Security checks rely on the loopback address, Host header, and Same-Origin Policy. Write operations can only modify declared value fields.
  • Environment requirements: Before installation, confirm that the Node.js version satisfies ^22.19.0 || >=24.0.0.

Conclusion

With this plugin, developers can focus on business logic rather than repetitive UI and security code. For detailed information, refer to the plugin catalog or the source repository.