# DeepSeek Harness (dsh) Setup with QCode

> **Last verified**: 2026-11-09 · 📄 Per official docs (DeepSeek Harness 0.2.2-rc.1, published on npm and GitHub on 2026-11-04; the repository docs were read on 2026-11-09)

## At a glance

| Item | Details |
|---|---|
| What it is | DeepSeek Harness (`dsh`) is an open-source agent harness developed by DeepSeek AI, with a Web UI started by `dsh web` |
| Models you can use | Claude ✅ (Anthropic Messages provider) · GPT ✅ · GLM / Kimi / DeepSeek / Qwen ✅ (OpenAI Chat Completions provider) · Gemini ❌ (QCode does not offer Gemini models for now) |
| Protocol & Base URL | OpenAI Chat Completions: `https://api.qcode.cc/openai/v1` · Anthropic Messages: `https://api.qcode.cc/api` |
| Where to configure | **Settings → Models** → **Add model provider** → **Custom model API** |
| Written to | `$DSH_HOME/profiles/<profile>/cordis.patch.yml`; the key goes to `$DSH_HOME/.credentials.yaml` |
| Official docs | [Configure models](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/guide/providers.md) · [repository](https://github.com/deepseek-ai/deepseek-harness) |

DeepSeek Harness is in developer preview. The official README says: "THERE WILL BE COMPATIBILITY-BREAKING CHANGES." Check the version you run against this page.

## Which protocol

The **API protocol** of a custom provider must be the one the gateway speaks. The picker offers three: OpenAI Chat Completions, OpenAI Responses and Anthropic Messages, stored as `openai-completions`, `openai-responses` and `anthropic-messages`. A provider speaks one protocol, so a gateway that serves two needs two providers.

QCode serves Claude only on the Anthropic protocol and GPT only on the OpenAI protocols; the four Chinese families work on both. See [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths). That gives two providers:

| Provider | API protocol | Base URL | Model IDs (examples) |
|---|---|---|---|
| `qcode` | OpenAI Chat Completions (`openai-completions`) | `https://api.qcode.cc/openai/v1` | `gpt-6-sol`, `deepseek-v4-pro`, `glm-5.3`, `kimi-k3`, `qwen3.8-max` |
| `qcode-claude` | Anthropic Messages (`anthropic-messages`) | `https://api.qcode.cc/api` | `claude-sonnet-5`, `claude-opus-5` |

The provider IDs are names you choose. Use the model IDs listed on [qcode.cc/models](https://qcode.cc/models), character for character; the Chinese ids are also listed in [Chinese Models](/docs/usage/cn-models). Do not add a trailing `/` to a base URL, and do not put `claude-…` IDs behind the OpenAI base URL.

## Install

DeepSeek Harness needs Node.js 24.9 or newer (the npm package declares `node >=24.9.0`, and the v0.2.2-rc.1 release notes say: "Raise the minimum supported Node.js version to 24.9."). Install Node.js, then run:

```sh
npx @deepseek-ai/dsh web
```

The command starts the Web UI at `http://127.0.0.1:3080` by default and opens it in the default browser for a local launch. An SSH launch only prints the host URL. Pass `--no-open` to run the server without opening a browser.

To run from a repository checkout instead:

```sh
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web
```

`$DSH_HOME` is the harness data root; it defaults to `~/.dsh` unless you set the `DSH_HOME` environment variable. Review the official [safety notice](https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md) before running the project.

## Configure

Model changes take effect on the next request without restarting the server.

1. Open the Web UI, then **Settings → Models**, and choose **Add model provider**.
2. Switch the card to **Custom model API**. It is meant for a relay, a company gateway, a self-hosted server, or any provider absent from the installed catalog.
3. Fill in the form for the first provider:
   - **Provider ID**: `qcode` (lowercase; it is permanent, so pick it deliberately)
   - **Display name**: `QCode` (optional)
   - **Base URL**: `https://api.qcode.cc/openai/v1`
   - **API protocol**: OpenAI Chat Completions
   - **API key**: your QCode key (starts with `cr_`)
4. In the form's **Models** list (the official guide calls it the model catalog), choose **Add model** and enter each model ID, for example `deepseek-v4-pro` and `gpt-6-sol`. **Fetch available models** asks the endpoint which models it serves; it is a convenience, and the official guide says that when it fails or lists nothing you add the model ids by hand and they work just the same. On QCode the OpenAI endpoint lists the GPT models, so add the Chinese IDs by hand.
5. Choose **Create provider**. Then repeat with Provider ID `qcode-claude`, Display name `QCode Claude`, Base URL `https://api.qcode.cc/api`, API protocol **Anthropic Messages**, the same key and the model `claude-sonnet-5`, and choose **Create provider** again.
6. Open the model picker and select a model. Selecting a model also makes it the default for new sessions.

Keys are write-only: after saving, the page receives a redacted descriptor, never the literal secret. The key is stored in `$DSH_HOME/.credentials.yaml`, while settings retain only its credential reference.

### What the page writes

For reference, the same providers in `$DSH_HOME/profiles/<profile>/cordis.patch.yml` look like this. For the standard `dsh web` launch `<profile>` is `web`, so the path is `$DSH_HOME/profiles/web/cordis.patch.yml`. The page writes this document for you; edit it by hand only if you need a setting the form does not offer.

```yaml
- id: llm-pi-ai
  config:
    providers:
      qcode:
        displayName: QCode
        apiKeyEnv: QCODE_API_KEY
        api: openai-completions
        baseURL: https://api.qcode.cc/openai/v1
        models:
          - id: deepseek-v4-pro
          - id: gpt-6-sol
      qcode-claude:
        displayName: QCode Claude
        apiKeyEnv: QCODE_CLAUDE_API_KEY
        api: anthropic-messages
        baseURL: https://api.qcode.cc/api
        models:
          - id: claude-sonnet-5
```

`apiKeyEnv` is a credential reference: the page derives it from the Provider ID (`qcode` → `QCODE_API_KEY`, `qcode-claude` → `QCODE_CLAUDE_API_KEY`) and stores the key you typed under that name. The official troubleshooting entry for `MISSING_CREDENTIAL` says: store the provider key through the Models page or supply the referenced environment variable. A Cordis config override replaces the complete entry config, so keep your other providers when you edit an existing override.

## Verify

1. Select a model you added in the model picker and send a short message such as `ping`.
2. Open [probe.qcode.cc](https://probe.qcode.cc), enter your QCode key and check that the request appears with that model.
3. To test the key and path without dsh:

```bash
KEY="cr_your_key"

# OpenAI Chat Completions provider
curl -sS https://api.qcode.cc/openai/v1/chat/completions \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"model":"deepseek-v4-pro","max_tokens":32,"messages":[{"role":"user","content":"ping"}]}'

# Anthropic Messages provider
curl -sS https://api.qcode.cc/api/v1/messages \
  -H "x-api-key: $KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-5","max_tokens":32,"messages":[{"role":"user","content":"ping"}]}'
```

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `MISSING_CREDENTIAL` | No key stored, or the referenced environment variable is empty | Store the key through **Settings → Models**, or export the variable named in `apiKeyEnv` before starting `dsh` |
| `UNKNOWN_MODEL` | The selected model is not in the provider's list | Select a configured model or add the model ID to the provider |
| Fetching available models returns 401 | Wrong key | Check the key; model discovery calls the OpenAI-compatible `GET /models` endpoint |
| Fetching lists nothing or fails | The endpoint's listing is in a format discovery does not read | Enter the model IDs by hand |
| `model_not_available_on_endpoint` | A `claude-…` ID was added to the OpenAI Chat Completions provider | Put Claude IDs in the Anthropic Messages provider with Base URL `https://api.qcode.cc/api` |
| 404 | Trailing `/` or wrong path prefix in a base URL | Compare with [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths) |
| The gateway refuses every request although the key and URL are right | Its request shape differs from OpenAI's | Official advice: start with `compat.supportsDeveloperRole: false` and `compat.maxTokensField: max_tokens` on the route |
| Only reasoning models fail | pi-ai sends their system prompt as the `developer` role | Set `compat.supportsDeveloperRole: false` |
| The Effort menu does not appear for a model you entered by hand | The model declares no reasoning levels | Turn on **Reasoning levels** in the model's **Model options** |

## Known limitations

- Developer preview: configuration fields and behaviour can change between releases; this page was checked against 0.2.2-rc.1, the version npm tags as `latest` on 2026-11-09.
- The form has no field for the `compat` switches; set them on the route in `cordis.patch.yml` as described in the official guide.
- A model you enter by hand declares no reasoning levels until you add them, and starts as text-only until you select **Image** in its **Model options** (see the official guide's sections on image input and reasoning effort).

## Related

- [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths) — protocol × model-family table
- [Chinese Models](/docs/usage/cn-models) — GLM / Kimi / DeepSeek / Qwen ids and paths
- [CodeWhale (DeepSeek-TUI)](/docs/ide/deepseek-tui) — another terminal agent with both protocols
- [Tool Compatibility Overview](/docs/ide/tool-compatibility) — which tools speak which protocol
- [T3 Code](/docs/ide/t3code) — a control surface that drives Claude Code and Codex
- [DeepSeek Harness guide on qcode.cc](https://qcode.cc/en/deepseek-harness-guide) — background and use cases