Docs

DeepSeek Harness

DeepSeek Harness keeps its own DeepSeek card and adds yours beside it. Five fields under “Add a custom provider” put Claude, GPT and Gemini in the same model picker, on one key.

Settings → Models → “Add a custom provider” takes five fields — Provider ID, display name, base URL, API protocol and API key — and puts Claude, GPT and Gemini in the same picker as the built-in DeepSeek card.

Settings → Models → Add a custom provider
# Settings → Models → Add a custom provider
#
#   Provider ID     kunavo          (lowercase, and permanent)
#   display name    Kunavo
#   base URL        https://api.kunavo.com/v1
#   API protocol    openai-completions
#   API key         sk-kn-...
#
# Then Model catalog → Fetch available models → Add selected,
# or type the ids by hand. The Models page writes $DSH_HOME/settings.yaml;
# the same provider in that file looks like this:

llm-pi-ai:
  providers:
    kunavo:
      apiKeyEnv: KUNAVO_API_KEY
      api: openai-completions
      baseURL: https://api.kunavo.com/v1
      models:
        - id: claude-sonnet-5
        - id: claude-opus-5
        - id: claude-haiku-4-5
        - id: gpt-5-6-sol
The base URL keeps the /v1 suffix. No sentence on the harness's page states the rule — but it shows the field three times in YAML and every one of them reads baseURL: https://gateway.example/v1 or https://vision.example/v1. Its troubleshooting entry settles it from the other side: “Model discovery calls the OpenAI-compatible GET /models endpoint”, which with that suffix is /v1/models — the route Kunavo answers. A bare origin here shows up as a 404, not as a bad key.
If you add reasoningEfforts, add compat.supportsDeveloperRole: false with it. The harness documents that a model declaring reasoning has its system prompt sent as role: "developer". Kunavo hoists that role onto the system turn for the Gemini and GPT families, but its OpenAI→Anthropic translator maps only system, user, assistant and tool and drops anything else — so on a claude- id the system prompt is discarded with no error at all. A model you enter by hand declares no levels, so a plain setup is unaffected; the moment the Effort menu appears for a Claude id, set that switch on the route or the model.
Kunavo serves no DeepSeek model. This provider sits beside the DeepSeek card, it does not replace it — keep your DeepSeek key where it is for deepseek- ids, and use this one for the Claude, GPT and Gemini ids in the table below. It also means the compat.thinkingFormat: deepseek switch the harness documents for “DeepSeek V4 behind an OpenAI-compatible gateway” has nothing to act on here.
This configuration was read off DeepSeek Harness's own documentation on the date below. Kunavo has not run DeepSeek Harness against its endpoint — not a session, not a streamed turn, not a tool round-trip. A published setup page is not a test, and the date on it says when someone else's docs were last read, not that anything was exercised. The curl below is the half you can check in ten seconds; the client's behaviour is between you and the harness, which is in developer preview and still moving.
Kunavo serves no embedding, text-to-speech or speech-to-text model, so this provider answers chat completions and nothing else. A harness plugin that transcribes audio or builds a vector index keeps whatever provider key it already has — adding this provider does not move those calls.

Step by step

  1. Create a key at /app/keys and copy it — it is shown once.
  2. Open the Web UI and go to Settings Models. Below the DeepSeek card, choose Add a custom provider — not Add provider, which only picks from the catalog dsh ships with.
  3. Fill in Provider ID (lowercase, and permanent — the docs say requests, saved sessions, model defaults and credential references all use it, and renaming means adding a new provider and deleting the old one), display name, base URL, API protocol = openai-completions and API key.
  4. Under Model catalog, choose Fetch available models — Kunavo answers GET /v1/models, so the picker fills itself. Tick what you want and choose Add selected. Ids typed by hand work just the same, and the docs say to fall back to that whenever discovery lists nothing.
  5. Pick a model in the composer and send a turn that touches a file, not a greeting — the harness leans on tool calling for most of what it does, so a first run that reads and edits something tells you more. Model changes take effect on the next request; the docs are explicit that nothing needs a restart.

Checked against the DeepSeek Harness “Configure models” page on September 21, 2026. Third-party settings move; if a field name here no longer matches what you see, that page is the authority, not this one.

Verify before you debug the client

One request settles whether a failure is the endpoint, the key, or the configuration file. If this returns JSON, the same base URL and key work in DeepSeek Harness.

# Settles whether a failure is the endpoint, the key, or the client.
curl -sS https://api.kunavo.com/v1/models \
  -H "Authorization: Bearer sk-kn-..."

Which model id to put in the field

Every text model is reachable as a model id — the live list is GET /v1/models, and the catalog with prices is on the models page. Rates are USD per 1M tokens, input / output.

Model idKunavo in / outWhere it fits in DeepSeek Harness
claude-sonnet-5$2.00 / $10.00the default working model for sessions that edit files
claude-opus-5$2.00 / $10.00planning a change that would be expensive to get wrong
claude-haiku-4-5$0.40 / $2.00cheap turns — triage, summaries, the loop that runs all day
gpt-5-6-sol$2.00 / $12.00a second opinion from another family, same key and same provider
gemini-3-1-pro$0.70 / $4.20long inputs, where the per-token rate is what decides the bill
Billing is per token from a prepaid balance with no monthly fee — see billing. On repeated context — which is most of what an editor or a chat client sends — prompt caching moves the bill more than the model choice does.

The fields the form does not have

The Models page and $DSH_HOME/settings.yaml are the same document — the docs say the adapters re-read it on the next request, and that when the browser is on the same machine as the server you can open it with Open configuration file in the Settings header. Four things matter for this endpoint, and only one of them has a field in the form:

  1. compat.supportsDeveloperRole: false — set it on the route or on the model for any claude- id that declares reasoning levels. The harness recommends this switch for gateways that reject the developer role; Kunavo does not reject it on the Claude path, it drops the message, which is worse to debug because nothing fails. The symptom is a model that behaves as if it never read your instructions.
  2. compat.maxTokensField — leave it alone. The harness pairs it with the switch above as the usual first fix, but Kunavo's own handler reads max_completion_tokens and falls back to max_tokens, so the default already works.
  3. reasoningEfforts — a model you enter by hand declares no levels, so the Effort menu does not appear and the endpoint's own default decides whether the model thinks. Declare the levels yourself if you want the menu; each key is a level and its value is the spelling sent as reasoning_effort.
  4. input: [text, image] — the docs are clear that this “states a claim about your endpoint rather than checking it”. Declaring images on an id that does not take them is not caught in the harness; the request is refused further along. Check the id on /models before you tick the box.

One structural point from the same page, worth knowing before you plan around it: “A provider speaks one protocol, so a gateway that serves two needs two providers.” Kunavo answers an Anthropic Messages surface as well, and anthropic-messages is one of the three values the API protocol field offers — but the harness's docs show a base URL example only for the OpenAI-compatible protocols, so this page does not put a value in that field for a form it has not seen settled. The openai-completions route above is the unambiguous one.

FAQ

How do I add a custom API provider to DeepSeek Harness?

Open the Web UI, go to Settings → Models, and choose "Add a custom provider" below the DeepSeek card — the separate "Add provider" button only picks from the catalog dsh ships with. The form asks for a lowercase Provider ID, a display name, a base URL, an API protocol and an API key, then at least one model under Model catalog. The Provider ID is permanent, because requests, saved sessions, model defaults and credential references all use it; renaming means adding a new provider and deleting the old one.

Does the DeepSeek Harness base URL need /v1 at the end?

Yes for an OpenAI-compatible endpoint, for example https://api.kunavo.com/v1. The documentation never states this as a rule, but it shows the baseURL field three times in YAML examples and all three carry the /v1 suffix, and its troubleshooting says model discovery calls the OpenAI-compatible GET /models endpoint — which with that suffix resolves to /v1/models. A base URL without it produces a 404 rather than an authentication failure.

Can DeepSeek Harness use Claude or GPT models instead of DeepSeek?

Yes. The API protocol field names the wire format, not the vendor: openai-completions is OpenAI Chat Completions, openai-responses is the Responses API, and anthropic-messages is the Anthropic Messages API. A custom provider speaking openai-completions passes your model id straight to the base URL you configured, so a Claude or GPT id resolves at that endpoint rather than inside the harness. The custom provider sits beside the built-in DeepSeek card rather than replacing it, so DeepSeek ids keep using your DeepSeek key.

Why does DeepSeek Harness behave as if it ignored my system prompt?

Check whether the model declares reasoning levels. The harness sends a reasoning model's system prompt as role "developer" rather than "system", because it infers request shape from the endpoint URL and treats an address it does not recognise as OpenAI itself. Kunavo maps that role onto the system turn for its Gemini and GPT families, but on the Claude path it maps system, user, assistant and tool and drops any other role — so the prompt disappears silently instead of returning an error. Setting compat.supportsDeveloperRole: false on the route or the model in $DSH_HOME/settings.yaml sends it as a system message again.

Why does "Fetch available models" return nothing or a 401 in DeepSeek Harness?

Discovery calls the OpenAI-compatible GET /models route with the base URL, protocol and key currently in the form, so a 401 points at the key and an empty list usually points at the base URL or at a listing format discovery does not read. The harness documents both outcomes and says to enter the ids by hand, which works identically. Settle which half is at fault with a plain curl against /v1/models using the same pair: JSON back means the fault is in the form, a 401 means the key, a 404 means the URL. Note also that a built-in provider is always answered from the installed catalog even when its base URL points elsewhere, so fetch through a custom provider to see what the endpoint really serves.