Bundle manifest vs profile: two layers, two jobs
What dsh.bundle and ~/.dsh/profiles/*.json each control, how to isolate web/tui/headless workspaces, and where the profile-switching boundaries actually live.
7 min read
What you'll learn
- How DSH's two-manifest model (bundle + profile) coordinates plugin loading
- What happens when the same plugin is active in multiple profiles
- Use
dsh --profile X plugin addto isolate plugin sets per workspace
Version
Compatible with: dsh 0.1.1-rc.2 (compiled from official apps/cli/README + docs/user/develop/basic/)
What each manifest controls
DSH uses two manifests: one describes how a plugin loads, the other describes which plugins a workspace uses:
| File | Location | Content | Read by |
|---|---|---|---|
dsh.bundle | repo root | plugin metadata (name / version / entry / services / patches) | CLI, once at install time |
~/.dsh/profiles/<name>.json | user workspace | which bundles to enable + load order + boot flags | Web/CLI, every start |
They don't replace each other: bundle says "this repo is a DSH plugin", profile says "today I want this combo of plugins". The same bundle can be in multiple profiles — each profile loads its own independent instance (via Cordis dispose), no cross-contamination.
Three common profile recipes
web(default): runs Web GUI, enables everything browser-friendly (vision, context dashboard, skins, pets)tui: runs terminal UI (dsh-tianshu-tui / dsh-TUI), TUI-specific plugins + tools that don't need GUIheadless: pure CLI, no UI; only essentials (search, memory, context)
Switch profiles:
dsh --profile web plugin add @liustack/modlens
dsh --profile tui plugin add @omdsh-dev/dsh-mnemon
Each profile maintains its own plugin list, no interference.
Isolation boundaries
- shared: model API keys, license cache, GitHub API token (global config)
- isolated: plugin list, enable/disable state, profile-level config (e.g.
cordis.services) - not shared: temporary caches (web's IndexedDB / tui's PTY history), preserved per profile across switches
Troubleshooting
- "installed a plugin but profile doesn't show it": probably installed to a different profile; check with
dsh --profile X plugin ls - "profile boot fails":
dsh --profile X --dump-configprints the actual load list - "two profiles cross-pollinate data": check
~/.dsh/profiles/for same-name profile collisions; profile names should be kebab-case with no spaces
FAQ
Can I edit a profile file directly?
Yes, at ~/.dsh/profiles/<name>.json. CLI also writes there, but manual edits get overwritten the next time CLI mutates that profile — back up first.
Can a bundle force itself into one specific profile only?
No. Bundles are profile-agnostic; either use CLI flags to pick the profile at install time, or check ctx.config.profile inside the plugin's apply(ctx).