How to configure DSH: config files, model keys, and profiles
DSH keeps its configuration under $DSH_HOME (default ~/.dsh). Before changing anything, inspect the active values with dsh --dump-config; the model key is set directly in the Web UI settings.
Where configuration lives
DSH uses the $DSH_HOME environment variable to locate its data directory, defaulting to ~/.dsh. It holds three kinds of things:
~/.dsh/profiles/<name>: one directory per profile, holding that profile's plugin dependencies (package.json) and its owncordis.patch.ymloverride layer.~/.dsh/cordis.patch.yml: the home-level, machine-wide preferences shared by all profiles.~/.dsh/sessions/: session records, kept separate from configuration.
The profile's package.json is never hand-written; the dsh plugin command creates and maintains it (source). So day-to-day "changing configuration" usually touches two places: settings in the Web UI, and the cordis.patch.yml overlay.
Inspect before you edit: dump-config
Look at the composed result before changing anything — it prevents most mistakes. Both commands work without actually booting DSH:
dsh --dump-config # the composed config tree
dsh --dump-default-config # the built-in defaults
--dump-config prints the final configuration after layering "profile bundles → profile overlay → home overlay → --patch flags", so you can see exactly which layer a value came from (source).
How configuration layers compose
DSH's effective configuration is composed over an empty root, layer by layer; later layers win per row. The order is:
- The bundles in the profile's
dsh.profile.bundleslist, in order; - The profile's own
cordis.patch.yml; - The home-level
~/.dsh/cordis.patch.yml; - Command-line
--patch <path>overlays, in argument order.
So the cleanest way to give a plugin custom config is to override its row's config by id in a cordis.patch.yml, instead of editing its source. Note that a patch replaces the entire config value of a row rather than deep-merging keys, so include every key you need when overriding.
Where the model key goes
Nine times out of ten, a model connection failure is a missing API key. Open Web UI Settings → Model, enter your DeepSeek API key and save; model routing takes effect immediately without a restart (source). Custom endpoints use OpenAI-compatible configuration; see the official providers docs.
A mistyped key or exhausted quota also shows up as "can't connect"; see DSH troubleshooting.
Common usage: port and workspace
Use --port to change the port, and pick a workspace on first open. The Web UI defaults to http://127.0.0.1:3080; if the port is taken, switch it:
dsh --profile web --port 8080
--port belongs to the web app, so it goes after --profile web; dsh web is an alias for --profile web. The new Web UI selects no workspace before you add one — click Select workspace to add a project directory, and the input becomes usable (source).
Understanding profiles
A profile is a bootable composition; web and headless are built in. dsh web boots the web profile; headless runs one-off jobs. A plugin installed into one profile only affects that environment, and profiles don't interfere with each other. Built-in profiles auto-initialize on first use; other profiles are created via the dsh plugin command.
To drop a profile entirely, delete ~/.dsh/profiles/<name>; DSH rebuilds web and headless on the next start. After editing, verify with dsh --dump-config once more. DSH is still in developer preview, so the file layout may change — defer to the official docs.
Source: dsh CLI README, official Quickstart
FAQ
Everything lives under $DSH_HOME, defaulting to ~/.dsh. Profile config is under ~/.dsh/profiles/<name>, and machine-wide shared config is ~/.dsh/cordis.patch.yml.
Run dsh --dump-config for the composed tree and dsh --dump-default-config for defaults, both without actually booting DSH.
Open Web UI Settings → Model, enter your DeepSeek API key and save; model routing takes effect immediately without a restart.
Run dsh --profile web --port 8080. --port belongs to the web app, so it goes after the profile flag.
A profile is a bootable composition; web and headless are built in. Each profile maps to ~/.dsh/profiles/<name>, and a plugin installed into one profile only affects that environment.
Sources
- dsh CLI README· deepseek-ai
- DeepSeek Harness documentation - Quickstart· deepseek-harness