DeepSeek Harness: Bundle and Profile
Last updated: 2026-08-31
A DSH project may need multiple run configurations — one for Web UI development, one for headless deployment, one for CI testing. A Profile is a named assembly scheme; a Bundle is a distributable configuration + code package. Together, they make DSH deployment as simple as switching channels.
📋 Prerequisites: Completed 12-local-plugin.md, understand cordis.yml configuration
1. What You'll Learn
- profile: named assemblies (web/headless)
- bundle: configuration + code distribution format
- dsh.profile and dsh.bundle fields
- dsh-base / dsh-web-app / dsh-headless
- Configuration layer composition order
- patch overlay mechanism
2. profile: Named Assembly
(1) profile Concept
A profile is a preset plugin combination scheme, identified by name:
web profile: → Includes Web UI plugins, interactive tools
headless profile: → No UI, pure API + script execution
ci profile: → Minimal plugin set, only what tests need
(2) Configuring a profile
Declare profiles in package.json:
{
"name": "my-dsh-project",
"dsh": {
"profiles": {
"web": {
"description": "Web UI mode for interactive development",
"plugins": [
"@deepseek-ai/dsh-web-app",
"@deepseek-ai/dsh-plugin-tools-interactive"
]
},
"headless": {
"description": "Headless mode for automation",
"plugins": [
"@deepseek-ai/dsh-headless",
"@deepseek-ai/dsh-plugin-tools-basic"
]
}
}
}
}
(3) ▶ Example 3
# Use web profile
pnpm dsh web --profile web
# Use headless profile
pnpm dsh headless --profile headless
(4) profile Composition
| Component | Description |
|---|---|
| Plugin list | Which plugins to include |
| Description | Profile's purpose |
| Default config | Default parameters for plugins |
3. bundle: Configuration + Code Distribution Format
(1) bundle Concept
A bundle is a profile + configuration + code packaging format, distributable like an npm package:
profile: Which plugins to select
bundle: Plugins + config + version lock → distributable package
(2) ▶ Example 2
dsh-bundle-my-team/
├── package.json ← dsh.bundle field
├── cordis.yml ← Default configuration
├── plugins/
│ ├── team-tools/ ← Built-in plugin
│ └── team-lint/ ← Built-in plugin
└── profiles/
├── web.yml ← web profile config
└── headless.yml ← headless profile config
(3) ▶ Example 3
{
"name": "@my-team/dsh-bundle",
"version": "1.0.0",
"dsh": {
"bundle": true,
"profiles": {
"web": "./profiles/web.yml",
"headless": "./profiles/headless.yml"
},
"baseConfig": "./cordis.yml",
"plugins": [
"./plugins/team-tools",
"./plugins/team-lint"
]
}
}
(4) Installing a bundle
# Install from npm
pnpm add @my-team/dsh-bundle
# Start using the bundle's profile
pnpm dsh web --bundle @my-team/dsh-bundle --profile web
4. dsh-base / dsh-web-app / dsh-headless
(1) Built-in Bundles
DSH provides three built-in bundles:
| Bundle | Description | Core Plugins Included |
|---|---|---|
| dsh-base | Minimal base set | core, llm, sessions, trajectory |
| dsh-web-app | Web UI full version | dsh-base + web-ui, interactive-tools |
| dsh-headless | No UI version | dsh-base + headless-runner, basic-tools |
(2) Dependency Relationships
graph TB
BASE[dsh-base<br/>core + llm + sessions] --> WEB[dsh-web-app<br/>+ Web UI + interactive tools]
BASE --> HEADLESS[dsh-headless<br/>+ Headless runner + basic tools]
(3) Default Behavior
Without the --bundle parameter, DSH defaults to dsh-web-app:
# Equivalent to pnpm dsh web --bundle dsh-web-app
pnpm dsh web
(4) Choosing a Base Bundle
# Minimal bundle (core only)
pnpm dsh web --bundle dsh-base
# Web UI bundle (default)
pnpm dsh web --bundle dsh-web-app
# Headless bundle
pnpm dsh headless --bundle dsh-headless
5. Configuration Layer Composition Order
(1) Multi-Layer Configuration Overlay
DSH's final configuration is composed from multiple layers, with increasing priority from bottom to top:
graph TB
L1[Layer 1: Bundle default config<br/>cordis.yml] --> L2[Layer 2: Profile config<br/>profiles/web.yml]
L2 --> L3[Layer 3: Project config<br/>project cordis.yml]
L3 --> L4[Layer 4: Patch config<br/>cordis.patch.yml]
L4 --> L5[Layer 5: CLI parameters<br/>--patch, --config]
(2) Overlay Rules
Bundle default: { plugins: [core, llm], port: 5173 }
Profile: { plugins: [+web-ui], debug: true }
Project config: { plugins: [+my-tool], port: 8080 }
Patch: { plugins: [+debug-tool] }
Final: { plugins: [core, llm, web-ui, my-tool, debug-tool],
port: 8080, debug: true }
(3) Plugin List Merging
| Operation | Effect |
|---|---|
| New plugin | Appended directly |
| Same-name plugin | Later layer overrides earlier |
$insert |
Appended to end of list |
$replace |
Replaces same-name plugin |
(4) Configuration Value Merging
Lower: { a: 1, b: { x: 1, y: 2 } }
Higher: { b: { y: 3, z: 4 }, c: 5 }
Result: { a: 1, b: { x: 1, y: 3, z: 4 }, c: 5 }
Nested objects deep-merge; scalar values override directly.
6. patch Overlay Mechanism
(1) cordis.patch.yml
The patch file is the highest-priority configuration override, suitable for temporary adjustments during development:
# cordis.patch.yml
plugins:
debug-tools:
$insert: ./dev-plugins/debug-tools
llm:
config:
debug: true
logRequests: true
(2) --patch Parameter
# Apply patch layer
pnpm dsh web --patch
# Don't apply patch
pnpm dsh web
(3) Multi-Environment Patches
config/
├── cordis.yml ← Base configuration
├── cordis.patch.dev.yml ← Development patch
├── cordis.patch.staging.yml ← Staging patch
└── cordis.patch.prod.yml ← Production patch
Switching environments:
# Development
cp config/cordis.patch.dev.yml cordis.patch.yml
pnpm dsh web --patch
# Production
cp config/cordis.patch.prod.yml cordis.patch.yml
pnpm dsh web --patch
(4) CLI Direct Override
The highest-priority configuration method:
# Override port directly
pnpm dsh web --config.port=8080
# Override LLM model directly
pnpm dsh web --config.plugins.llm.config.model=deepseek-reasoner
❓ FAQ
dsh.bundle fields telling DSH how to load configuration and plugins.--dump-config to view the final configuration: bash pnpm dsh web --patch --dump-config This shows the result of all layers merged, making it easy to locate conflict sources.--bundle dsh-base to load only the minimal core set, then assemble your own via cordis.yml..gitignore excluding cordis.patch.prod.yml.📖 Summary
- profile is a named plugin assembly scheme (web/headless/ci etc.)
- bundle is profile + config + code in a distributable package
- Three built-in bundles: dsh-base (minimal), dsh-web-app (Web UI), dsh-headless (no UI)
- Configuration five-layer overlay: Bundle → Profile → Project → Patch → CLI; later layers override earlier
- cordis.patch.yml is the highest-priority config file;
--patchenables it --dump-configviews the final merged configuration; essential for troubleshooting conflicts
📝 Exercises
1. ⭐ Basic: Add dsh.profiles fields to your project's package.json, defining web and headless profiles. Start DSH with each profile and compare the loaded plugin lists.
2. ⭐⭐ Intermediate: Create a cordis.patch.dev.yml that loads the debug-tools plugin and enables LLM request logging in dev mode. Start with --patch and use --dump-config to verify the patch layer's override effect.
3. ⭐⭐⭐ Challenge: Create a complete bundle package with a custom profile, two built-in plugins, and a default configuration. Publish to a local npm registry (or use the file: protocol), install from another project, and start using this bundle.