DeepSeek Harness CLI: What Each dsh Entry Point Does Before You Have an API Key
DeepSeek Harness uses the dsh command to launch different profiles. The web profile starts a browser interface, while headless runs one task from the command line and exits. The help text also includes a tui entry point. We tested all three on Windows, first without credentials and then with an invalid API key. This article records the errors and startup behavior we observed before receiving an AI-generated answer. In version 0.2.1-rc.5, the tui command shown in the help text does not work on a fresh installation.
The tests produced three main results. First, dsh headless exits with code 1 when no API key is configured and reports MISSING_CREDENTIAL. With an invalid key, it receives an HTTP 401 response and then reports an AUTH error; the displayed key is masked as ****t123. Second, dsh web starts without an API key and serves the interface at 127.0.0.1:3080. The browser URL includes a token, and the model picker remains empty until you configure a model and key. Third, dsh tui fails on version 0.2.1-rc.5 because no tui profile template is included. The following sections show the commands and output.
The entry points and what each one needs before it does anything
The launcher's own help lists three ways in. We ran all three the same afternoon, on a machine with no DeepSeek key stored anywhere:
| Command | What it does | With no key stored |
|---|---|---|
dsh web | Serves the browser UI on 127.0.0.1:3080 | Boots fine. Key and model get configured in the UI |
dsh headless "task" | Answers one task, prints result, exits | Exits 1 immediately - MISSING_CREDENTIAL |
dsh tui | Help text: "boot a custom profile" | Never boots - profile "tui" does not exist on this release |
In short, web starts the interface and lets you configure credentials there; headless stops with a named error if no key is available; and tui fails on a fresh installation because its profile is not included in this release. The sections below show the output from each test.
dsh headless: what happens without an API key
dsh headless "say hi" with no credentials stored:
dsh: MISSING_CREDENTIAL: llm-deepseek: no API key for provider route "deepseek-official"; store DEEPSEEK_API_KEY through the credentials service (the web Models page writes it), or export DEEPSEEK_API_KEY in the launching environment
The command exited with code 1 in less than a second. The error identifies the missing item: an API key for the deepseek-official provider route. It also gives two ways to add the key: save it through the credentials service (the web app's Models page does this) or set DEEPSEEK_API_KEY in the shell before launching dsh. This makes it clear why the command stopped.
Then we exported a deliberately fake key (sk-faketest123) and ran the same command. The failure came in two stages:
[llm-deepseek-api-key] model listing from https://api.deepseek.com/models failed (LlmError: ... answered HTTP 401); using the bundled catalog
dsh: AUTH: Authentication Fails, Your api key: ****t123 is invalid (request_id: be043bd1-...)
The command again exited with code 1. The output shows that dsh first tried to retrieve the model list from the API. After the request returned HTTP 401, it used the bundled model catalog instead. The later AUTH error indicates that the API rejected the supplied key. The output masks most of the key but leaves the last four characters visible, and it includes a request_id that may help when contacting DeepSeek support. If you believe the key is valid, check that it was copied completely and does not contain extra spaces. Our API key guide explains how to create a key.
dsh web: boots without a key, then waits for configuration
dsh web --no-open printed exactly one line and kept running:
dsh web: http://127.0.0.1:3080/?token=…
Before printing the local URL, the launcher checks several options. The --host value must be one specific IPv4 or IPv6 address assigned to a local interface; wildcard addresses are rejected. TLS configuration requires both a certificate and a key file. Additional browser-trust authorities are supplied one at a time with --trusted-host. See dsh web --help for the full list. Note that dsh web --help describes the web command, while dsh --help describes the main launcher.
The first screen displays a version 0.2 preview notice. The composer continues to show "please choose a model" until a model is selected and an API key is configured. We found that the credentials service creates a file under $DSH_HOME when a key is saved. We checked the file's existence and location, but did not inspect how it is encrypted. For screenshots of the first launch and the 401 response, see our installation guide.
dsh tui: the entry point the help text promises and the release does not ship
Run dsh tui on 0.2.1-rc.5 and it fails before any UI attempt:
Error: dsh: profile "tui" does not exist; create it with 'dsh plugin --profile tui add <package>'
In the installed code for version 0.2.1-rc.5, the profiles initialized automatically from shipped templates are web, headless, sdk, sdk-minimal, and acp. There is no tui template. The README's example includes the condition "assuming the tui profile is installed," but the help examples leave that condition out. Copying the help example on a fresh installation therefore produces the error shown above.
The error message suggests creating the tui profile by adding a terminal-app plugin or using --from-default-profile. In other words, tui is a profile that users must set up; it is not a terminal interface that is ready to launch on a fresh install. The desktop profile name is reserved for the Electron app, and the npm CLI rejects boot and config-dump requests for it. See the plugins guide for more about how profiles and plugins are assembled.
Profiles are directories, and knowing that saves debugging time
Every entry point above resolves to a directory under $DSH_HOME/profiles/. On our machine after the tests, exactly two existed: web and headless - created on first use, as the README says. Each holds a package.json (with the profile's bundle list under a dsh key), a cordis.patch.yml override layer, and pnpm workspace files.
Each entry point uses a directory under $DSH_HOME/profiles/. After our tests, the web and headless directories had been created automatically, as described in the README. Each directory contains a package.json file with the profile's bundle list under a dsh key, a cordis.patch.yml override file, and pnpm workspace files.
| What we counted | web profile | headless profile |
|---|---|---|
| Plugin entries in the composed default tree | 191 (187 distinct packages) | 98 |
| Entries disabled by default | 32 | - |
Counts from --dump-default-config on our install, 4 November 2026. The web profile carries roughly twice the stack of headless - session logging, the browser UI, and the typert registry are web-side - which is why headless is the profile to point scripts at once credentials exist.
The errors we triggered used the format dsh: NAME: explanation and returned a nonzero exit code. The table below lists the errors we observed and the message each one provides:
Every failure we triggered came out as dsh: NAME: explanation with a nonzero exit. That is deliberate design - the names are the API:
| Error name | When we saw it | What it is actually telling you |
|---|---|---|
MISSING_CREDENTIAL | headless, no key | No key for the provider route; store via credentials service or export DEEPSEEK_API_KEY |
AUTH: Authentication Fails | headless, fake key | The API rejected the key; masked key and request_id included; exit 1 |
profile "…" does not exist | tui | Not a shipped template in this release; create it via dsh plugin or --from-default-profile |
invalid profile name | not reproduced, by code inspection | Empty name, path separators, dots, or "node_modules" are rejected before touching disk |
We could not test a real headless run end to end - that needs a funded API key, which we deliberately do not put on test machines. Everything up to the credential gate, including both error paths above, is from our own runs.
Frequently asked questions
- What is the difference between dsh web and dsh headless?
- dsh web serves a browser interface on localhost:3080 for interactive use. dsh headless runs one task from the command line, prints the result, and exits. The web interface can start without a key, because you configure the model and key in the UI. The headless command requires a key before it will run.
- Why does dsh tui say the profile does not exist?
- Version 0.2.1-rc.5 does not include a tui profile template. The automatically initialized templates are web, headless, sdk, sdk-minimal, and acp. The help examples omit the README's condition that the tui profile must already be installed. You can create a tui profile by adding a terminal-app plugin to it.
- Where does dsh store the API key?
- In a credentials file under $DSH_HOME, written either by the web app's Models page or by importing an environment variable before launch. We verified the file appears there on first use; we did not audit its encryption.
- Can I run dsh web so other devices on my network can reach it?
- Do not expose the web interface to other devices without checking the security settings first. The --host option rejects wildcard addresses and accepts only a specific local interface IP. The interface also uses a per-boot token and browser-trust settings. Remote access requires deliberate TLS and trusted-host configuration.
- dsh headless failed with AUTH - is my key wrong?
- An AUTH error means the API rejected the key supplied in the request. Check the last four characters shown in the masked key against the key you intended to use. Also check for missing or extra characters. If the key still appears correct, generate a new one and consult the request_id when contacting DeepSeek support.
Sources and what we could not test
| Claim | Where it came from | Date checked |
|---|---|---|
| MISSING_CREDENTIAL wording, two key-storage routes; fake-key two-stage failure with masked key and request_id | our own runs on 0.2.1-rc.5, Windows 11 + Node v22.22.2 | 4 Nov 2026 |
| dsh web flags: single-IP --host, wildcard rejected, TLS pair required, --trusted-host | dsh web --help as shipped in 0.2.1-rc.5 | 4 Nov 2026 |
| Shipped profiles web/headless/sdk/sdk-minimal/acp; tui and desktop absent or reserved | README and dsh-app-boot source installed with 0.2.1-rc.5 | 4 Nov 2026 |
| 191/98 plugin-entry counts, 32 disabled, empty profile dependencies | our --dump-default-config counts on our install | 4 Nov 2026 |
No funded DeepSeek API key exists on our test machine, so nothing past the credential gate was exercised: no real headless answers, no interactive chat, no plugin activation inside a live session. The tui profile was not assembled and booted (that is a build-it-yourself path, and out of scope for a what-works-out-of-the-box page). The credentials file's encryption internals were not audited.