nihaozyj7
dsh-desktop
Go + Wails desktop shell for DeepSeek Harness: native window, engine supervision, self-update, and preview source builds
- Stars
- 0
- Language
- Go
- Created
- Aug 14, 2026
- Updated
- Aug 14, 2026
Introduction
DSH Desktop — DeepSeek Harness Desktop Shell
A Go + Wails desktop shell for DeepSeek Harness: native window, supervised Node engine, self-update, and preview source builds. The agent runtime stays 100% inside the harness — this project only wraps it.
Screenshots


Features
- Custom frameless title bar — logo, shell + harness version chips, settings / minimize / maximize / close controls, draggable, double-click to maximize.
- Settings panel — update check, update feed, repository URL, port + LAN WebUI toggle, open data/log folders, restart engine, about, quit.
- Live theme unification — on startup the shell extracts the web UI's palette from its CSS, persists it, and binds the desktop chrome to the page's own CSS variables (
var(--dsw-alias-*, …)), so the title bar follows the web theme (light/dark) automatically. - Release-based self-update — signed manifests (sha256 + ed25519), atomic versioned payloads, automatic rollback.
- Preview builds — no release available? Pull the repository source, compile locally, and switch to a
preview-<commit>engine. Great for testing the latest code. - Full backend permissions — the engine runs with
DSH_PERMISSION_MODE=danger-full-access(sandbox unrestricted, no approval prompts); the shell adds no restriction of its own. - No console window — the engine runs hidden (
CREATE_NO_WINDOW); a loading page with a spinner covers startup.
Architecture
┌───────────────────────────────────────────────────────────────┐
│ dsh-desktop.exe (Wails shell, Go) │
│ ├─ Frameless window (WebView2) │
│ ├─ AssetServer: reverse proxy → engine │
│ │ Host/Origin/Referer normalized to loopback, so the /api │
│ │ browser-trust fence accepts the desktop webview; HTML │
│ │ responses are decorated with the desktop chrome │
│ ├─ engine: child-process supervisor (readiness/restart/swap) │
│ └─ updater: release channel + preview source builds │
└───────────────────────────┬───────────────────────────────────┘
│ http://127.0.0.1:<OS-assigned>
┌───────────────────────────▼───────────────────────────────────┐
│ Engine payload (in %LOCALAPPDATA%\DSHByDesktop\versions\<v>) │
│ node.exe + closure/ — the packaged dsh web engine │
│ (build via DSHByDesktop/engine/build-engine.mjs inside a │
│ deepseek-harness checkout) │
└───────────────────────────────────────────────────────────────┘
Key design points:
- Shell and engine are separated. Updates swap only
versions/<v>/engine; the runningdsh-desktop.exeis never replaced, so Windows file locking is a non-issue. User data lives inDSH_HOME(default~/.dsh) and is never touched by updates. - Readiness signal. The engine prints
dsh web: http://127.0.0.1:<port>once the Loader tree settles; the shell parses the port, arms the proxy, and reloads the window.--port 0means no port conflicts. - The webview is a trusted loopback client. The proxy rewrites Host/Origin/Referer to the engine's loopback authority, so the harness's /api trust fence treats the desktop UI exactly like a page opened from
127.0.0.1. - LAN exposure is a shell listener, not an engine bind. The engine stays loopback-only; an optional
0.0.0.0:<port>listener in the shell proxies external requests through the same trust-normalizing proxy.
Repository layout
DSHByDesktop/
main.go entry (--headless / --build-preview / --version)
shell/ Go sources (engine supervisor, proxy, updater, theme, UI embed)
shell/ui/ injected chrome (style.css, markup.html, app.js)
engine/build-engine.mjs engine packaging (pnpm deploy + closure carrier)
scripts/ icon generation, dist assembly, update signing, local feed server
build/ Wails resources (icons)
frontend/ no-op placeholder for the Wails toolchain
Prerequisites
- Windows 10/11 x64 with WebView2 (bundled with Windows 11; Evergreen runtime otherwise).
- To build the engine you need a checkout of deepseek-harness with this project placed at its
DSHByDesktop/directory, plus:- Node.js ≥ 22.19, pnpm
- Go (1.22+), gcc (Wails requirement), Wails CLI v2
Building (inside a deepseek-harness checkout)
pnpm install
pnpm run build # harness lib + web dist
# engine: deploy the closure + node.exe carrier (~300 MB, AV-safe)
node DSHByDesktop/engine/build-engine.mjs --skip-build
# optional single-file SEA (trips heuristic AV; only for whitelisted/signed setups)
# node DSHByDesktop/engine/build-engine.mjs --skip-build --sea
# shell
cd DSHByDesktop && wails build && cd ..
# assemble dist + update zip
node DSHByDesktop/scripts/assemble-dist.mjs --zip
Artifacts land in DSHByDesktop/dist/: dsh-desktop.exe, engine/…, dsh-desktop-windows-amd64.zip, update-windows-amd64.json.
Running
DSHByDesktop/dist/dsh-desktop.exe # desktop window
DSHByDesktop/dist/dsh-desktop.exe --headless # engine only, prints the URL (CI/debug)
DSHByDesktop/dist/dsh-desktop.exe --build-preview # source preview build, then exit
First run copies the bundled engine into %LOCALAPPDATA%\DSHByDesktop\versions\<version>\engine; afterwards the engine always runs from the versioned directory.
Self-update
The update feed defaults to the repository's release asset update-windows-amd64.json (next to dsh-desktop-windows-amd64.zip). The shell checks at startup and every 4 hours, and on demand from the settings panel:
{
"version": "0.2.0",
"url": "https://…/dsh-desktop-windows-amd64.zip",
"sha256": "<zip sha256>",
"signature": "<ed25519 over the sha256 hex>",
"releaseNotes": "…"
}
Download → sha256 verify → ed25519 verify (public key embedded in shell/updater.go) → extract to versions/<v> → swap the current pointer → restart the engine; a failed boot within 120s rolls back automatically.
Signing keys. Manifests are signed with an ed25519 keypair. Generate your own and embed the public key in shell/updater.go:
node DSHByDesktop/scripts/gen-signing-key.mjs # writes scripts/update-signing-key.json
node DSHByDesktop/scripts/sign-update.mjs <version> DSHByDesktop/dist/dsh-desktop-windows-amd64.zip "notes"
Preview builds (from source)
In the settings panel → 预览版(从仓库构建) enter a repository URL and start. The shell:
git fetchthe latest source (defaulthttps://github.com/deepseek-ai/deepseek-harness; any fork works)pnpm install+pnpm run build- Packages the engine with
build-engine.mjs - Installs it as
preview-<commit>, switches, and restarts (with rollback)
Requires git, Node ≥ 22 and pnpm on the machine. Progress is shown live in the panel.
Permissions model
The shell imposes no permission restrictions:
- Frontend: the proxy normalizes Host/Origin/Referer to loopback, making the desktop webview a trusted loopback client of the /api fence.
- Backend: the engine runs with
DSH_PERMISSION_MODE=danger-full-access— harness preset: sandbox unrestricted + approvalnever.
Configuration
%LOCALAPPDATA%\DSHByDesktop\settings.json:
{
"updateFeed": "https://github.com/…/releases/latest/download/update-windows-amd64.json",
"repoURL": "https://github.com/deepseek-ai/deepseek-harness",
"autoCheck": true,
"webPort": 0,
"exposeWeb": false
}
webPort (0 = auto, used when exposeWeb is on) and exposeWeb are also editable in the settings panel. DSH_DESKTOP_UPDATE_FEED and DSH_DESKTOP_ENGINE are optional environment overrides.
Known limitations
- Windows/amd64 only so far; macOS/Linux need platform runners and their WebViews.
- The engine exe is unsigned — code-sign the distribution to avoid SmartScreen warnings.
- No system tray; closing the window quits the app.
- LAN exposure is intentionally opt-in and exposes full agent permissions — enable only on trusted networks.