DeepSeek Harness: Loading Local Plugins
Last updated: 2026-08-31
Understanding the plugin loading mechanism is the key leap from "wrote a plugin" to "efficiently developing plugins." cordis.yml is DSH's configuration hub, and the --patch overlay mechanism lets you flexibly layer local plugins without modifying the default configuration.
--patch mechanism is "layering, not replacing" — the default configuration stays unchanged, and your local modifications are overlaid on top. This lets development debugging and production deployment share the same base configuration.
📋 Prerequisites: Completed 11-first-plugin.md, able to create a minimal plugin
1. What You'll Learn
- cordis.yml configuration file details
$insertand$replaceoperations- Absolute path vs. relative path selection
--patchoverlay mechanism principles--dump-configto view final configuration- Local development and debugging workflow
2. cordis.yml Configuration Details
(1) Configuration File Location
cordis.yml is DSH's core configuration file, located at the project root:
my-dsh-project/
├── cordis.yml ← Main configuration
├── cordis.patch.yml ← Patch configuration (optional)
├── package.json
└── src/
(2) ▶ Example 2
# cordis.yml basic structure
plugins:
plugin-name:
# Plugin configuration items
enabled: true
config:
key: value
# Global configuration
hostname: localhost
port: 5173
(3) Plugin Entry Format
Each plugin entry contains three pieces of information:
| Field | Description | Example |
|---|---|---|
| Plugin name | The key is the plugin identifier | my-plugin: |
| Path | Where to load from | $insert or npm package name |
| Configuration | Parameters passed to the plugin | Fields under config: |
plugins:
# npm package plugin
@dsh-plugin/database:
config:
connection: "postgresql://localhost/mydb"
# Local plugin
my-local-plugin:
$insert: /home/alice/dev/my-plugin
config:
debug: true
3. $insert and $replace Operations
(1) $insert: Append a Plugin
$insert adds a plugin to the existing plugin list:
plugins:
my-tool:
$insert: /home/alice/dev/dsh-plugin-my-tool
Effect is equivalent to:
Default plugin list: [core, llm, tools, shell, ...]
After insert: [core, llm, tools, shell, ..., my-tool]
(2) $replace: Replace a Plugin
$replace replaces an existing plugin with a new implementation:
plugins:
# Replace the default LLM adapter with a custom one
llm:
$replace: /home/alice/dev/custom-llm-adapter
Effect:
Default: llm → @deepseek-ai/dsh-plugin-llm
Replaced: llm → /home/alice/dev/custom-llm-adapter
⚠️ $replace must specify an existing plugin name; you cannot replace a non-existent entry.
(3) ▶ Example 3
plugins:
# Append local tool
my-tool:
$insert: /home/alice/dev/dsh-plugin-my-tool
# Replace default shell with a secure version
shell:
$replace: /home/alice/dev/dsh-plugin-safe-shell
# Append another local plugin
my-monitor:
$insert: /home/alice/dev/dsh-plugin-monitor
(4) Operation Priority
When the same plugin has both $insert and $replace:
Priority: $replace > $insert
If the $replace target doesn't exist, it falls back to $insert behavior.
4. Path Strategy
(1) ▶ Example 1
plugins:
my-plugin:
$insert: /home/alice/dev/my-plugin
Advantages:
- Not affected by working directory
- Clear path during debugging
- Reusable configuration across projects
Disadvantages:
- Hardcoded user path, not portable
- Team members have different paths
(2) Relative Paths
plugins:
my-plugin:
$insert: ./plugins/my-plugin
Relative paths are resolved based on the directory containing cordis.yml.
Advantages:
- Portable, suitable for team collaboration
- Plugins can be versioned with the project
Disadvantages:
- Depends on the working directory at startup
- Path calculation is complex for nested directories
(3) Path Selection Recommendations
| Scenario | Recommended | Reason |
|---|---|---|
| Personal development | Absolute path | Clear, unambiguous |
| Team collaboration | Relative path | Portable, consistent across environments |
| CI/CD | Relative path | Build environment paths vary |
| Temporary debugging | Absolute path | Quick to locate, no path issues |
5. --patch Overlay Mechanism
(1) Configuration Layering Model
DSH configuration is built from multiple layers:
graph TB
BASE[Base Layer<br/>Default Configuration] --> BUNDLE[Bundle Layer<br/>dsh-base / dsh-web-app]
BUNDLE --> PROFILE[Profile Layer<br/>web / headless]
PROFILE --> PATCH[Patch Layer<br/>cordis.yml + --patch]
PATCH --> FINAL[Final Configuration]
Each layer overrides same-named configuration items from the previous layer, similar to CSS cascade priority.
(2) --patch Parameter
# Apply patch layer at startup
pnpm dsh web --patch
Without --patch, DSH only reads the default configuration and ignores $insert/$replace in cordis.yml. With --patch, the override operations in cordis.yml take effect.
(3) cordis.patch.yml
In addition to the main configuration, you can use cordis.patch.yml as an extra patch layer:
# cordis.patch.yml — only for development environments
plugins:
debug-tools:
$insert: ./dev-plugins/debug-tools
--patch reads both cordis.yml and cordis.patch.yml, with the latter having higher priority.
(4) Overlay Merge Rules
Base config: { a: 1, b: 2, c: 3 }
Patch layer: { b: 20, d: 4 }
─────────────────────────────
Final config: { a: 1, b: 20, c: 3, d: 4 }
- Same-named fields: Patch layer overrides base layer
- New fields: Directly appended
- Unaffected fields: Remain unchanged
6. --dump-config to View Final Configuration
(1) Basic Usage
pnpm dsh web --patch --dump-config
Outputs the fully merged final configuration:
# === Merged Configuration ===
hostname: localhost
port: 5173
plugins:
core:
enabled: true
llm:
enabled: true
config:
provider: deepseek
tools:
enabled: true
my-tool: # ← Your insert
$insert: /home/alice/dev/my-tool
config:
debug: true
debug-tools: # ← Added by patch.yml
$insert: ./dev-plugins/debug-tools
(2) Debugging Configuration Issues
When a plugin doesn't load as expected, use --dump-config to troubleshoot:
# Troubleshooting steps
pnpm dsh web --patch --dump-config > config-dump.yml
# Check if your plugin appears in the final configuration
# Check if $insert path is correct
(3) View Specific Plugin Only
# Filter to view specific plugin configuration
pnpm dsh web --patch --dump-config | grep -A 10 "my-plugin"
7. Local Development and Debugging Workflow
(1) Standard Development Loop
graph LR
CODE[Write Plugin Code] --> REG[Register in cordis.yml]
REG --> START[Start dsh web --patch]
START --> TEST[Test Plugin Behavior]
TEST --> BUG{Bugs?}
BUG -->|Yes| CODE
BUG -->|No| DONE[Done]
(2) Quick Iteration Tips
Alice's typical workflow when developing a tool plugin:
# 1. One-time cordis.yml configuration
cat > cordis.yml << 'EOF'
plugins:
my-tool:
$insert: /home/alice/dev/dsh-plugin-my-tool
EOF
# 2. Development loop
# Edit code → restart → test
pnpm dsh web --patch
# When done testing, Ctrl+C to stop
# 3. Verify configuration
pnpm dsh web --patch --dump-config | grep my-tool
(3) Multi-Plugin Parallel Development
Bob developing two plugins simultaneously:
# cordis.yml
plugins:
tool-a:
$insert: /home/bob/dev/dsh-plugin-a
tool-b:
$insert: /home/bob/dev/dsh-plugin-b
Develop in separate terminals; both plugins load when restarting DSH.
(4) Temporarily Disabling a Plugin
No need to uninstall — just comment it out in the configuration:
plugins:
my-tool:
$insert: /home/alice/dev/my-tool
# experimental-tool: # Temporarily disabled
# $insert: /home/alice/dev/exp-tool
❓ FAQ
cordis.yml is the Cordis framework's configuration, managing plugin loading and overrides. dsh.config.yaml is the DSH application's configuration, managing modes, approval policies, etc. They complement each other and don't conflict.package.json.--patch, DSH uses the default configuration and ignores cordis.yml. This is intentional — to prevent development configuration from accidentally affecting production.cordis.patch.yml in the project root is supported. If you need multiple patch sets, you can manually switch file contents.dsh web --patch for cordis.yml changes to take effect. See 18-hot-reload.md for HMR mechanisms.📖 Summary
- cordis.yml is DSH's plugin configuration hub, containing plugin paths and configuration items
$insertappends plugins,$replacereplaces existing plugins- Absolute paths suit personal development, relative paths suit team collaboration
--patchenables the overlay mechanism, layering cordis.yml on top of default configuration--dump-configshows the final merged configuration — a powerful tool for troubleshooting loading issues- Development loop: edit code → register in cordis.yml →
dsh web --patch→ test
📝 Exercises
1. ⭐ Basic: Register the hello-world plugin from the previous lesson using $insert in cordis.yml, and use --dump-config to confirm it appears in the final configuration.
2. ⭐⭐ Intermediate: Register the same plugin using both absolute and relative paths, and use --dump-config to compare the output differences between the two configurations.
3. ⭐⭐⭐ Challenge: Create two local plugins A and B, and $insert both in cordis.yml. Try using $replace to replace one of DSH's built-in tool plugins with your custom version, and verify the replacement with --dump-config.