DeepSeek Harness desktop external CLI: dsh web and RPC

TroubleshootingPublished 2026-10-30Author: DeepSeek Plugin Market
DeepSeek HarnessDSHdesktopdsh webRPCexternal accesstoken
An external CLI cannot attach to a DeepSeek Harness desktop session: the token only goes over Node IPC and no attach command exists. Use dsh web plus /connect.

The desktop app really is running an authenticated API, and the port is live — but you cannot get the key to enter it. The desktop host starts with --no-open --host 127.0.0.1 --port 0, and the token-bearing URL is handed only to the Electron shell over Node IPC, so external clients have no supported pairing flow (#10956). Identify the host first, then choose an architecture.

DeepSeek Harness: Step 1: identify which host you are attaching to

The desktop app and dsh web share the same session data but authorize outside clients in completely different ways; misidentify the host and every command after that is wasted.

  1. Look at processes: the desktop app is an Electron shell plus an embedded host; dsh web is a Node process starting the host directly.
  2. Look at launch arguments: the desktop uses --no-open --host 127.0.0.1 --port 0 with a random port.
  3. Look at terminal output: dsh web prints a line like dsh web: http://127.0.0.1:3080/?token=….
  4. Look at CLI capability: the current CLI has only profile launch, --dump-config*, and dsh plugin, with no attach/session/send.
  5. A quick check: dsh session --help on rc.3 reports profile "session" does not exist, because it treats session as a profile name.

DSH plugin: Step 2: why the desktop cannot be entered

Three hard boundaries stack up: the token only travels over IPC, there is no pairing flow, and the session lock forbids a second writer.

  1. Token boundary: the token-bearing URL is sent only to the Electron shell (desktop-host L30, L103-L104), so external clients have no way to obtain it.
  2. Pairing boundary: remote access offers only a policy bit for "non-owner principals", but no flow registers such principals, so the only caller type is owner, admitted by the process's launch token.
  3. Lock boundary: an active session holds a cross-process flock on session.lock, so a second host may list sessions but gets session/writer-held on submit.
  4. One more at the source level: the desktop host does print the dsh web: …?token= line, but Electron wires it into the app's own stdout (host-process.ts), so it is visible only when launching the app binary from a terminal.
  5. Port and token change on every start, and this path carries no documentation promise for the desktop app.

DeepSeek Harness: Step 3: the supported alternative architecture

Use a dsh web host, exchange the launch URL for a cookie, then operate sessions over RPC.

  1. Start it: dsh web --host 127.0.0.1 --port 3080, and note the token-bearing URL printed in the terminal.
  2. Exchange for a cookie:
bash
B=http://127.0.0.1:3080
curl -s -c jar.txt -o /dev/null \
  "$B/connect?token=<launch-token>&interactions=none"
# expect 302 and an API cookie
  1. Define an RPC call function (argument keys are the TypeScript parameter names):
bash
rpc() { curl -s -b jar.txt -H 'content-type: application/json' \
  -d "{\"type\":\"client-request\",\"rpcId\":\"$RANDOM\",\"method\":\"$1\",\"payload\":{\"args\":$2}}" \
  "$B/api/$1"; }

rpc session/list '{"_request":{}}'
rpc session/prompt '{"request":{"requestId":"req-1","sessionId":"session-…","mode":"queue","content":[{"type":"text","text":"follow-up"}]}}'
  1. Read history with session/page and session/follow; manage the queue with session/updateQueue and session/cancel.
  2. If the client should answer approvals on the user's behalf, change interactions to answer.
  3. Without a cookie, session/list returns 401 — the fastest signal that the chain is or is not connected.

Community measurement: /connect returned 302 pointing at ./api/remote.mux, after which session/create and session/prompt returned {"accepted":true}; starting another dsh web on the same home could list the session, but prompt submission returned session/writer-held.

DSH Plugin: Migrating existing desktop sessions

Both share session files under $DSH_HOME, so after quitting the desktop app you can open the same data with dsh web and continue — the cost is exactly the restart you wanted to avoid.

  1. Quit every desktop process.
  2. Start dsh web with the same DSH_HOME.
  3. Find the original session in the list and confirm the history is intact.
  4. Then submit follow-up prompts using the RPC sequence above.
  5. The whole process needs no session file copying and no workspace rebuilding.

DeepSeek Harness: Known limitations

This RPC is an internal wire format, not a documented public API.

  1. args keys are TypeScript parameter names, and the list interface literally takes _request, which looks odd but is correct.
  2. Argument shapes may change across rc versions, so regression-test before upgrading.
  3. The remote access policy currently covers only non-owner principals; do not expect it to grant external clients access.
  4. There is no attach or pairing entry for the desktop app today, and the rc.4 and 0.2.2-alpha.2 release notes add none.
  5. To get that capability, file an Ideas request and wait for upstream to decide.

DSH plugin: Cautions

Use the supported host instead of prying a token out of Electron.

  1. Do not try to extract the token from the Electron process. It is unsupported and out of scope here.
  2. Do not use a second host to force-write the same session. session/writer-held is the lock working correctly.
  3. Do not hardcode the RPC as a stable API. After upgrading, run session/list once to verify.
  4. Mind the cookie scope. Changing port or hostname requires a fresh /connect.
  5. Record the launch arguments. With a random port, only the URL in the terminal output tells you the address.

If your goal is only "run a task once from a script", headless is simpler than attaching to the desktop app; only when you need to operate an existing session is the dsh web route worth it.

A one-line selection rule: to operate an existing session cross-process, use dsh web RPC; for one-shot execution, use headless; if you need neither, do not open external access at all.

If you are already on the desktop app and cannot restart, external access is unsolvable in the current version — waiting for upstream to provide a pairing entry is the only direction.See dsh web authentication required: how to fix the prompt for the related case.

FAQ

Can an external CLI or API client connect to the DeepSeek Harness desktop app?

No, DeepSeek Harness 0.2.1-rc.3 does not support it, and the rc.4 and 0.2.2-alpha.2 release notes add nothing. The desktop host serves the same API set, but the token is handed only to the Electron shell over Node IPC, so external clients have no supported authorization entry.

dsh session --help in DeepSeek Harness reports profile session does not exist — did I install it wrong?

No, you did not install it wrong: the DeepSeek Harness CLI currently has only profile launch, --dump-config*, and dsh plugin families, with no attach/session/send, so dsh session is treated as a profile name and reports that the profile does not exist.

Why does starting a second DeepSeek Harness host against the same session also fail?

Starting a second host against the same session fails in DeepSeek Harness because an active session holds a cross-process flock on session.lock. A second host can list the session, but submitting a prompt returns session/writer-held.

What is the supported approach in DeepSeek Harness?

The supported approach in DeepSeek Harness is to start a separate dsh web host: it prints a launch URL containing a token, exchange that with /connect for an API cookie, then call RPC methods such as session/list and session/prompt.

Can existing DeepSeek Harness desktop sessions be moved to dsh web and continued?

Yes, existing desktop sessions can be moved to dsh web in DeepSeek Harness, but you must quit the desktop app. Both share sessions under $DSH_HOME, so after closing the desktop app you can open the same data with dsh web and continue — at the cost of exactly the restart you wanted to avoid.

Related Terms

Desktop Host
Desktop Host is the host process embedded in the desktop app, started with --no-open --host 127.0.0.1 --port 0, serving the same authenticated API as dsh web, but its launch token is given only to the Electron shell.— https://github.com/deepseek-ai/deepseek-harness/discussions/10956
/connect
/connect is the dsh web authorization entry that exchanges a token-bearing URL for an API cookie. It returns 302, after which the cookie is required to call session RPCs.— https://github.com/deepseek-ai/deepseek-harness/discussions/10956
session/writer-held
session/writer-held is the error returned when submitting a prompt indicates another process holds write access to that session, guaranteed by the cross-process flock on session.lock.— https://github.com/deepseek-ai/deepseek-harness/discussions/10956
RPC method
RPC methods are the session operation interfaces exposed by dsh web, such as session/list, session/prompt, and session/page. Argument keys are passed through by TypeScript parameter name and are an internal format that may change across versions.— https://github.com/deepseek-ai/deepseek-harness/discussions/10956

Sources