YichuAI/deepseek-harness-vscode

DeepSeek Harness Connector

Native VS Code client for DeepSeek Harness. Same workspace, same session, same agent runtime — VS Code and the browser share one Harness session.

미분류deepseekdeepseek-harnessvscode

DeepSeek Harness Connector

DeepSeek Harness Connector for VS Code

Same Harness. Same Workspace. Same Session.
Your agent keeps running wherever it already is. This puts a native VS Code client in front of it: attach to the Harness on this machine, read the session the browser is reading, answer its approvals, and review every edit in VS Code's own diff.

English | 简体中文

Install · Open VSX · Download VSIX · Changelog · How it got built

An independent, unofficial community project — not affiliated with, endorsed by, or published by DeepSeek.

The trailer: it finds your Host by itself, and one session answers in two windows

The 30-second trailer, cut down to its two product beats. The silence is deliberate — there is no narration, the film says it in type. Play it · How it got built (中文版: STORY.zh-CN.md)

At a glance

What it isA client for a dsh web you already have running. It attaches to that Harness and continues its workspaces and sessions inside VS Code.
What it is notAn agent, a model provider, or a replacement for either. None of the orchestration is reimplemented here — it stays in the Harness.
What it needsVS Code ≥ 1.85, and a Harness on the same machine as the window. That is the one hard constraint; see Remote development.
Installcode --install-extension lucasliang.harness-connector-deepseek

Jump to: What it does · What's new · Quick start · Configuration · Commands · Remote development · Limitations · Development · Design

What it does

  • Continues the session you already have. Workspaces and sessions are read from the running Host. Refresh that session in a browser and you see exactly what VS Code sent.
  • Answers approvals and agent questions — for the conversation you are looking at. Both waterfalls are settled by this plugin, so a run is never blocked on a browser tab you have closed. The Host forwards every session's waterfalls down one socket, so a card is drawn only when the frame names your session; a question raised in a browser tab on another session is not rendered here, and switching to that session brings it back.
  • Reports what each turn changed, and can undo it — one hunk at a time. Fed by the Host's own turn record, so it covers a file a shell command edited, not only what a file tool reported. Each hunk has its own undo; the file-level undo reverts whatever is left. Both check the file's current bytes first and refuse rather than overwriting you.
  • Right-click to ask about things. Select code, a file in the explorer, or a change in the diff editor and the context menu offers Explain / Fix / Review — pre-filled with a prompt and the right @ mention, including the line range for a selection.
  • Opens VS Code's own editor for anything that is code. A diff is a real diff editor; a path opens the file. Nothing is reimplemented in the webview.
  • Finds the Host by itself, including the desktop app, which starts its Host on an OS-assigned port that changes on every launch.
  • Four ways to obtain a session, and the default picks for you. Mint one from the harness's own credential store (zero configuration, but it means reading a file that also holds your API keys), let the extension start dsh web and take the launch URL it prints, or paste a launch URL yourself. auto — the default since v0.2.8 — does the first and falls back to the second. See How the session is obtained.
  • Starts no process unless you ask it to. The default attaches to the Host you already have running.
  • Can install its own Host, on whichever machine that means. DeepSeek Harness: Install Host runs the install in the extension host — on a Remote-SSH window, that is the remote — so you never end up with dsh on your laptop and a remote that still has none. Managed launch also retries through npx by itself when dsh is not on PATH, which needs no install at all.

How it connects

This is not a Cursor replacement, a Claude Code replacement, or a full coding agent. It connects VS Code to your already-running local dsh web instance:

Browser ─────┐
             │
             ▼
       DeepSeek Harness
             ▲
             │
VS Code ─────┘

VS Code reads the workspaces and sessions the browser already has, and continues the same session — so a browser refresh of that session sees exactly what VS Code sent.

Screenshots

One session in two surfaces: the DSH Web UI in the browser on the left, the DSH Connector panel in VS Code on the rightA native VS Code diff of a file the agent changed
The DeepSeek Harness sidebar in VS Code: connected host, an agent question with the option that was chosen, and the turn's changed-files cardThe DSH Web UI on its own

Top left: the same session at the same moment in two clients — nothing imported, mirrored or forked. Top right: "Diff" is VS Code's own diff editor, not a webview imitation — the left side is the text the plugin captured before the change. Bottom left: the conversation lives in the sidebar, tool rows and changed-files card included. Bottom right: the browser side, untouched.

What's new in v0.4.1

Pick the model in the editor, and prove "Open Web UI" works without opening a browser.

Two changes landed. Model and thinking-depth selection now lives in VS Code — a model ▾ / thinking ▾ bar under the composer, and a Model group in the ⚙ Settings panel, both going through the Host's session/selectModel and persisting as a durable model/selection event. And npm run verify-webui mints a cookie through the extension's own BrowserSessionAuth and hits the live Host: 401 with no cookie, 200 with the minted one — a one-command end-to-end check instead of trusting the unit test.

Model & thinking depth, in the editorA model ▾ / thinking ▾ bar under the composer applies from the next turn. The ⚙ Settings panel has a Model group too, with "reset to Host default" and "fall back when unavailable". The choice goes through the Host's session/selectModel and lands as a durable model/selection event — reload the session and it is still there.
npm run verify-webuiEnd-to-end proof that Open Web UI works: it mints a cookie through the extension's own BrowserSessionAuth, then hits the live Host — 401 with no cookie (the Host gates /), 200 with the minted one. Run it before a release instead of trusting the unit test.

Verification:

GateResult
Protocol assertions602 assertions — 533 in v0.3.0
End-to-end chains96 across 3 of 5 chains
Live Host (0.2.1-rc.2)42/42, both authentication paths
Version gate52 checks

Most of the 26 new assertions pin the model-selection persistence and that request/header can still override it.

The release before this one — v0.4.0 — closed three dead ends (Open Web UI, privileged approvals, and a transcript that re-sent itself) and added the settings panel and first-run prompt. Its notes, and every earlier release's, are in CHANGELOG.md.

Requirements

  • VS Code ≥ 1.85
  • A local dsh web (default port 3080), either already running or started for you by the default sessionMode: "auto".
  • The Harness must be on the same machine as the VS Code window. That is the one hard constraint; Remote development covers what it means for Remote-SSH, WSL and containers.

Quick start

  1. Start Harness locally — or skip this step and let the extension do it (it is the default):

    dsh web
    # → http://127.0.0.1:3080/?token=<43-char token>
    

    Recent Harness builds print a launch URL carrying a per-process token. You do not need it for the default setup — use it to open the Web UI in a browser if you want both surfaces side by side. (The token is a per-process secret compared on every request, not a single-use grant, so reloading that URL keeps working.)

    Skipping this step is the default: deepseekHarness.sessionMode is "auto", so when nothing answers on the port the extension starts the Host itself and takes the URL off its console. See How the session is obtained.

    Older builds serve /api/* unauthenticated and need no token at all — the plugin detects which it is talking to, so if no launch URL appears you can simply ignore this step.

  2. Install from the VS Code Marketplace or via command line:

    code --install-extension lucasliang.harness-connector-deepseek
    

    Or install the VSIX from GitHub Releases:

    code --install-extension harness-connector-deepseek-0.4.1.vsix
    
  3. Nothing to configure. The default sessionMode: "auto" first does what credentials does — read the browser-session signing secret out of $DSH_HOME/.credentials.yaml and mint the cookie itself, with no token to paste — and if nothing is listening, it starts dsh web instead. Read How the session is obtained for what that implies, and for the two modes that never open that file.

  4. Open a folder in VS Code that you want to bind to a Harness workspace.

  5. The DeepSeek Harness activity-bar icon appears; the extension auto-connects. If your folder matches an existing Harness workspace, its sessions appear in the dropdown. Pick one and continue the conversation.

  6. No matching workspace? Just type a prompt and hit Send — the workspace and session are created automatically.

  7. Reference a file with @ — type @ in the input and a completion list appears; pick one and it is inserted as a mention (@src/main.ts). Right-click a file in the explorer and choose Add to Harness Chat, or select text in the editor and choose Send Selection to Harness to insert @src/main.ts:L10-L20. Nothing is pasted into your message: the mention is a pointer, and the host tells the agent to open the file itself. That keeps your prompt text (and its KV cache) stable no matter how large the file is.

  8. Open the same session in your browser at http://127.0.0.1:3080/ — both surfaces see the same turn.

How the session is obtained

The harness authenticates /api/* with a browser-session cookie, and there are four ways to get one here. deepseekHarness.sessionMode picks which.

auto (default) — mint if you can, start a Host if you cannot. The two questions that looked like one: who are you is answered by minting from $DSH_HOME/.credentials.yaml, while is anything listening is answered by the socket. auto mints first and only reaches the launcher when the port answers nothing, so a machine that already has a Host running behaves exactly as it did before, and a machine nobody prepared gets one started. Modes below are the two halves, for when you want one of them and not the other.

credentials — mint it locally, and nothing else. dsh web keeps a persistent signing secret in $DSH_HOME/.credentials.yaml (client-connection/browser-session). The cookie is an HMAC over {version, authority, issuedAt, expiresAt} keyed by that secret, the cookie carries no trace of the launch token, and the secret is created once and reused by every later dsh web process — so anything that can read the file can mint a byte-identical cookie. The extension reads it and mints the cookie itself. That is why there is nothing to paste. It never starts a Host: choosing this mode on a machine with nothing running is a decision to run dsh web yourself.

managed — let the extension start the Host. It runs deepseekHarness.launchCommand (dsh web --port 0 by default), reads the launch URL off the console of a process it owns, and redeems that token. No credential file, no paste. The Host it started is stopped when the window closes.

paste — start it yourself and hand over the URL. Run dsh web, copy the dsh web: http://… line, and run DeepSeek Harness: Use Launch URL. Nothing is read from disk and nothing is started.

About minting, since the default may do it and it is a real privilege:

  • That same file holds your model API keys. Reading it is permission-equivalent to full authority over this harness home. It is not an escalation, and it does not defeat a boundary that protects you from yourself — but the extension's process can then see secrets that have nothing to do with a VS Code client.
  • It skips the per-process launch-token gate. That gate defends against remote callers (DNS rebinding, CSRF), not against code already running as you.
  • managed is the answer to both of those. If reading that file is not a trade you want to make, switch modes — you lose nothing but the process the extension starts.
  • No credential material is logged, sent to the webview, or put in a diagnostics report. The log records that a mint happened, never the material. The launch URL is held in memory for the one thing it is for and is redacted in every log line that mentions it. The cookie lives in VS Code's secret storage — the OS keychain — never in settings.json. DeepSeek Harness: Diagnostics exports a report you can read in full before sending it anywhere.

This is a workaround, and we would rather it were not necessary. The sanctioned flow is exchanging the per-process launch token, and managed/paste do exactly that — but nothing writes the token to disk, so a client that did not start the Host itself had no way to obtain it, which is what made reading the signing secret the only zero-configuration path. A first-class local-client authorization flow would close the gap properly: a socket, or a one-shot token file written 0600 and scoped to a single client. Until Harness ships one, the three modes above are the honest menu.

When a route cannot run

The connect error names the cause and the file or command it looked for. There is no silent fallback.

SituationWhat to do
$DSH_HOME points elsewhere and the env var is not setset DSH_HOME for the VS Code process, or start dsh web with the default home
dsh web has never run in this harness homerun it once — the client-connection/browser-session record is created then, or set sessionMode: "managed" so only the launcher is used
No dsh command on PATH under managedmanaged launch retries through npx first; if that fails too, the panel offers Install Host; on Windows and macOS the desktop app also registers dsh for you
managed ran but dsh exited immediatelyusually the port is already taken — the log carries the child's own last lines
You are in paste mode and have not pasted yetrun DeepSeek Harness: Use Launch URL

A cookie obtained this way still lives its own life: the extension stores it in VS Code's secret storage (OS keychain — never settings.json), it survives dsh web restarts, and it is only re-derived when it expires or you change host/port (the cookie name is dsh-auth-<sha256(host:port)>, so it is bound to the authority that minted it).

Configuration

Everything below is also editable from the panel: ⚙ Settings & help lists each knob with the sentence that explains it, and carries the actions that used to live only in the command palette — Find running Host, Install Host, Diagnostics, Show logs and Open Web UI.

SettingDefaultNotes
deepseekHarness.host127.0.0.1Exactly three values are accepted — 127.0.0.1, localhost, ::1. Any other value is refused before a socket is opened. See Remote development.
deepseekHarness.port3080The default dsh web port. Override if you started dsh web --port <n>.
deepseekHarness.showSystemMessagesfalseShow plugin-injected system messages (runtime context, approval notices). Hidden by default; toggle live with the SYS button in the webview header.
deepseekHarness.sessionModeautoHow a session is obtained. auto mints locally from $DSH_HOME/.credentials.yaml when it is readable and starts dsh web when nothing answers; credentials only mints; managed only starts; paste waits for you to supply a launch URL. See How the session is obtained.
deepseekHarness.launchCommanddsh web --port 0The command sessionMode: "managed" runs. The default binds an OS-assigned port, because managed launch reads the real port off the launch URL and pinning one only adds a way to fail. Run through a shell, so wrappers and npx work. If the default command is not found, managed launch retries once through npx — which on a remote fetches and starts the Host there; a command you set yourself is never substituted. Read only when a Host is started; changing it does not disturb a running one.
deepseekHarness.autoApproveApprovalsfalseAutomatically answer incoming approval requests with allowed-once. Off by default — enabling it means tools run without per-call confirmation.
deepseekHarness.autoDiscovertrueWhen the configured port answers nothing, look for a dsh Host elsewhere on loopback (pinned webserver.port first, then the OS listener table, confirmed by the Host's own refusal text). Needed by the desktop app, which starts its Host on an OS-assigned port. The discovered port is session-local and never written to your settings.

Commands

  • DeepSeek Harness: Connect / Reconnect / Disconnect — Reconnect (also the ⟳ button in the panel header, and the always-visible button in the status row) drops whatever is live and negotiates a fresh session
  • DeepSeek Harness: Diagnostics — one document with the runtime version, this extension's version, connection state, which capabilities the Host actually serves, and the last error. Offers a Copy redacted report action; nothing credential-bearing is included
  • DeepSeek Harness: Clear Session Token — drop the stored cookie and reconnect (a fresh one is minted under credentials, or a fresh Host is started under managed; use it before switching dsh web instances)
  • DeepSeek Harness: Use Launch URL — paste the dsh web: http://… line a Host printed and adopt its session. The paste route, usable in any mode
  • DeepSeek Harness: Switch to Auto and Connect — what the status row's repair button runs: persist sessionMode: "auto" and force a reconnect, which is the one-click answer to "nothing is listening" under credentials
  • DeepSeek Harness: New Session (in the active workspace)
  • DeepSeek Harness: Refresh Sessions
  • DeepSeek Harness: Move to Right Side Bar — dock the view in the secondary side bar (like Chat) so it stops competing with the file explorer. Also available via the ⇲ button in the webview header.
  • DeepSeek Harness: Toggle Plan Mode — flip /plan on the active session
  • DeepSeek Harness: Set Permission Preset — pick (or type) a preset such as read-only / workspace-write / danger-full-access
  • DeepSeek Harness: Compact Session Context — request /compact
  • DeepSeek Harness: Fork Session — branch off the current session and switch to the fork
  • DeepSeek Harness: Rename Session — pin a title (stops automatic regeneration)
  • DeepSeek Harness: Archive Session — archive it out of the active workspace list
  • DeepSeek Harness: Attach File to Session — stage local images/files for the next prompt (images ride session/prompt as inline parts; other files upload to POST /api/session/uploadFileBinary and are referenced by receipt) — also available via the 📎 button and by pasting or dropping into the composer
  • DeepSeek Harness: Install Host — install the dsh CLI in the extension host, which on a remote connection is the remote machine. Confirms first and names that machine; runs npm i -g @deepseek-ai/dsh; never elevates, so a system-owned npm prefix reports its own EACCES instead of escalating
  • DeepSeek Harness: Open Web UI — opens the token-bearing launch URL in your browser. Whichever route left the extension holding a URL — managed launch, or a launch URL you pasted — it uses it; credentials mode has no token to add and says so
  • DeepSeek Harness: Show Logs (the DeepSeek Harness outpu