zneoxlab
deepseek-harness-app
DeepSeek Harness Desktop — A native desktop app for DeepSeek Harness (dsh). Open the app and start using the agent harness immediately — no terminal, no browser, no setup
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 13, 2026
- Updated
- Aug 15, 2026
Introduction
DeepSeek Harness App
Cross-platform desktop client for DeepSeek Harness
A native shell around the official dsh web UI — fused title bar, tray residency, and a settings page with update management (short: dsh-app)
[!NOTE] DeepSeek Harness App (dsh-app) is not an official DeepSeek product. It wraps the local DeepSeek Harness (
dsh) CLI into a desktop app: it automatically detects your Node/npm/dsh environment, installs or upgrades missing pieces with one click, starts/reuses a plugin-enableddsh webwhen the app launches, and gives the official web UI the desktop experience it deserves — a fused title bar, tray residency, notifications, autostart, global shortcuts and connect modes.
Why not a full rewrite?
The official dsh ships a complete web UI (sessions, projects, permissions, skills, plugins, media — everything lives there). The official ACP server (@deepseek-ai/dsh-acp) is automation-only: it creates fresh sessions but cannot load / list / resume / fork existing ones, so it cannot power a full desktop console.
That is why DeepSeek Harness App builds on the official web UI instead of reinventing it: we add only what a browser cannot — a native shell, tray residency, and desktop integrations.
Why this is different from fork-based shells
Some desktop clients fork or vendor the DeepSeek Harness source and ship their own “core”. That makes the package heavier, can drift from upstream, and often freezes the core until the shell project updates it. dsh-app does the opposite:
| Fork/vendor-based shells | dsh-app | |
|---|---|---|
| Core | Bundle or fork the dsh codebase, often with modified internals | Use the official local @deepseek-ai/dsh CLI from npm — no fork, no rewrite |
| Update path | Wait for the shell maintainer to merge upstream changes | Sync official dsh releases from npm/GitHub Releases; one-click check and upgrade |
| Independence | If the shell stops being maintained, the bundled core can be stuck | dsh core is official and can always be upgraded independently of this App |
| Footprint | Often Electron + copied/duplicated web UI | Lightweight Tauri native shell + official web UI; dsh runs from your local installation |
| Browser access | The shell may own/alter the only running server or fork the UI | App starts or reuses the standard local dsh web — the same service stays reachable in your browser |
Practical highlights:
- Automatic Node / CLI detection — the startup wizard checks Node, npm, and dsh in order; it finds dsh from
DSH_BIN→ npm global → PATH → common install dirs, and reports versions and paths. - One-click install / upgrade — missing Node? The app downloads an official managed Node into
~/.dsh-app/node(no admin). Missing dsh? It installs@deepseek-ai/dshthrough npm automatically (mirror-aware in Chinese environments). Both App and dsh CLI can be checked and upgraded from the settings page. - Automatic start/stop management — on launch the App reuses a bridge-enabled
dsh webat127.0.0.1:3080, or starts its owndsh --profile dsh-app --port 0; on quit it cleans up the whole process tree. Your manually started plaindsh webis left untouched, and launching the App does not block browser access. - dsh CLI version management — the status row and DSH App settings show the current dsh version/source/service URL; the latest version is checked against the npm registry, and you can update with one click or copy the command.
- Left-bottom connection status — the sidebar footer status row shows a colored dot and connected/disconnected text, plus dsh CLI version and service URL on hover; click to copy connection info.
- Autostart — optional autostart (
--hidden) starts the App silently in the tray, ready to show the desktop shell on demand.
Contents
- Why this is different from fork-based shells
- Features
- Screenshots
- How it connects
- Install
- First run & troubleshooting
- Develop & build
- Testing failure scenarios
- Project structure
- Roadmap
- License
Features
| Area | What you get |
|---|---|
| Smart connect | Detects dsh CLI (DSH_BIN → npm global → PATH → common install dirs); reuses a running bridge-enabled instance on 127.0.0.1:3080, otherwise starts its own dsh --profile dsh-app --port 0 on a free random port (a plain dsh web you started manually is left alone) |
| Node / CLI auto detection | Startup wizard checks Node, npm, and dsh step by step, reports versions/paths, and warns when the managed Node is too old |
| dsh CLI detection | Startup wizard when the CLI is missing — copy the install command, one-click install/upgrade, re-check with one click |
| One-click environment install | Missing Node or dsh? Install them inside the app: official managed Node to ~/.dsh-app/node, then @deepseek-ai/dsh via npm global (mirror-aware, no admin required) |
| Fused title bar | A borderless window with a title bar fused into the system frame, per-platform window buttons: macOS uses the native title bar entirely (real system traffic lights, native rounded corners and shadow); Windows draws Win11-style square caption buttons at the top-right; Linux draws neutral circle buttons at the top-left. Windows 11 rounds the whole window automatically (undecorated + shadow). The strip is the drag region; double-click maximizes. Title bar colors follow the in-app theme (dark / light / system) on every platform |
| Sidebar status row (bottom-left) | A status capsule (colored dot + 已连接 / 未连接) at the very bottom-left of the sidebar below the settings button, app version on the right; hover shows dsh CLI version and service URL, click copies the connection info (registered through the official sidebar.footer.action slot; the settings row moves up one slot) |
| DSH App settings page | A page registered into the official settings panel: app info (version, source-code link) + update management against GitHub Releases; dsh CLI info (version / source / service URL) + CLI version management (latest check against the npm registry, one-click update, copy update command) |
| Model Presets | Fused into the original model configuration, no separate page: on the first boot the bridge server pre-writes mainstream channels (DeepSeek / OpenAI / Anthropic / Google Gemini / OpenRouter / xAI / Moonshot / MiniMax / Zhipu GLM / Mistral / Groq / Together) into the official llm-pi-ai namespace — they show up under Settings → Models as already-configured routes with their built-in model catalogs enabled; you only fill the API key there. Once any provider is configured the presets never run again, so removed channels never come back |
| System tray | Close-to-tray; left-click shows the window; Quit cleans up the whole dsh process tree (no orphans) |
| Single instance | A second launch focuses the existing window instead of spawning another server |
| Windows ready | Falls back to DSH_PERMISSION_MODE=danger-full-access when unset (no confinement backend on Windows) |
| i18n | UI follows the system language (Simplified Chinese / English), including the DSH App settings page |
| Native icons | Official dsh favicon (the whale) as the app icon across platforms |
Desktop layer (P1): desktop notifications · autostart (silent tray via --hidden) · global shortcut (default CmdOrCtrl+Shift+Space) · connect modes (smart / explicit remote, container or self-hosted web UI — http/https only, reachability-checked) — the switches live in the official Web UI's "Desktop" settings section (injected via the settings.section slot)
All desktop pieces are injected through the official DSH plugin mechanism (dsh-app-bridge, the oh-dsh route): the app owns a dedicated dsh-app profile that loads the bridge bundle — your own web profile is never touched. The App is only a native shell: it does not fork or vendor the dsh core, does not bundle an Electron runtime, and does not replace the official web UI.
Screenshots
From the current Windows development build.
| Startup — detecting CLI | dsh CLI missing — install wizard |
|---|---|
![]() | ![]() |
| Home — official dsh web UI inside the shell |
|---|
![]() |
| DSH App settings page — app + dsh CLI update management | Sidebar bottom-left status row — connection status & info |
|---|---|
![]() | ![]() |
How it connects
App starts
│
├─ Frontend checks for the dsh CLI (dsh_detect)
│ ├─ found → calls dsh_connect
│ └─ missing → shows the install wizard (stable, never hijacked)
│
├─ dsh_connect: does 127.0.0.1:3080 carry the desktop bridge?
│ (GET /dsh-app/status → {"ok":true})
│ ├─ yes → reuse it (browser & desktop share one dsh process)
│ └─ no → spawn `dsh --profile dsh-app --port 0`
│ (app-owned profile, hidden console window, random port),
│ parse the ready line, navigate the window
│
└─ Quit from the tray → taskkill the whole process tree
The frontend drives the connection (instead of the Rust side auto-connecting), so the install wizard is never skipped by a fast race. Only bridge-enabled instances are reused — a plain dsh web you started for browser development is left untouched, and the app starts its own plugin-enabled instance. Reusing 127.0.0.1:3080 means browser and desktop share the same dsh process; even when the app starts its own profile instance, the standard local dsh web remains the underlying server, so launching the App does not block or take over your browser access.
Install
1. Get the app
Download the installer for your platform from Releases (Windows NSIS, macOS DMG, Linux AppImage/deb — coming as builds are published).
2. Install the dsh CLI
DeepSeek Harness App does not bundle dsh — it detects it on your machine:
npm install -g @deepseek-ai/dsh
Alternatively set DSH_BIN to point at a dsh executable (e.g. a local build's lib/bin.js).
If Node or
dshis missing, the app's setup wizard can install them for you: it downloads an official managed Node into~/.dsh-app/node, then installs/upgrades@deepseek-ai/dshthrough npm automatically — no terminal required. The same one-click flow is available later from the settings page for upgrades.
That's it — launch the app and it connects automatically.
First run & troubleshooting
"dsh CLI required" wizard shows even though I installed it — the app probes at launch; click "I've installed it — re-check" to rescan.
Windows permission warning — when DSH_PERMISSION_MODE is unset, the app falls back to danger-full-access (Windows has no confinement backend) and logs a warning. Set it explicitly if you want a different mode.
Nothing found on PATH but dsh works in your terminal — check npm root -g; if the global dir is not on PATH, set DSH_BIN to %APPDATA%\npm\node_modules\@deepseek-ai\dsh\lib\bin.js (Windows) or the equivalent.
Develop & build
Requirements: Node 20+, Rust stable, @deepseek-ai/dsh installed (or DSH_BIN set).
npm install
npm run tauri dev # dev run with hot reload
npm run tauri build # release build (NSIS on Windows by default)
Only build NSIS (skip MSI/WiX):
npm run tauri build -- --bundles nsis
Rebuild the bridge plugin bundle alone (the app ships it as an external file):
cd dsh-app-bridge && npm run build
Testing failure scenarios
Set the DSH_APP_MOCK environment variable to simulate startup states:
| Value | Effect |
|---|---|
| (unset) | Normal flow |
missing-cli | Simulates a missing dsh CLI → install wizard |
no-server | Simulates 3080 free + spawn failure → connection error |
PowerShell:
$env:DSH_APP_MOCK = "missing-cli"; .\src-tauri\target\release\dsh-app.exe
Project structure
dsh-app/
├─ src/ # React + TS frontend (light splash / connection status)
│ ├─ App.tsx # detection-driven connect flow
│ ├─ WindowControls.tsx # splash-phase fused title bar (native macOS strip / Linux circles / Windows caption buttons + drag)
│ └─ i18n.ts # system-language UI (zh/en) + error-code l10n
├─ dsh-app-bridge/ # cordis plugin injected into the official Web UI
│ ├─ src/server.ts # /dsh-app/status marker endpoint (bridge detection)
│ │ # + first-run model presets: pre-writes mainstream
│ │ # channels into the official llm-pi-ai model config
│ │ # (virgin config only; no separate UI)
│ ├─ src/client/index.tsx
│ │ # fused title bar (per-platform buttons + status dot)
│ │ # + theme sync, "DSH App" settings page
│ │ # (app + dsh CLI update management)
│ ├─ scripts/build.mjs # client bundle (factory-wrapped) + server bundle
│ └─ cordis.patch.yml # bundle layer (insert row for the loader)
├─ src-tauri/
│ ├─ src/lib.rs # Rust shell: tray, single instance, smart connect, tree-kill,
│ │ # dsh-app profile bootstrap, window-control + app_info commands
│ ├─ src/connect.rs # (P1) connect modes & settings storage
│ ├─ src/notify.rs # (P1) desktop notifications
│ ├─ src/desktop.rs # (P1) autostart & global shortcut
│ ├─ capabilities/ # IPC ACL: app commands + remote 127.0.0.1 access
│ └─ tauri.conf.json # window / bundle config
├─ assets/screenshots/ # screenshots used in this README
└─ docs/ # design docs & fix records
Roadmap
- P0 (done) — minimal usable shell: smart connect, single instance, tray, tree-kill, CLI detection wizard, i18n
- P2 (done, core) — desktop fusion via the DSH plugin mechanism (
dsh-app-bridge): fused title bar with connection status, "DSH App" settings page (app update management + dsh CLI update management), model presets fused into the official model configuration (first-run server-side pre-write of mainstream channels intollm-pi-ai, no separate UI), app-owneddsh-appprofile - P1 (done) — Desktop enhancement layer: notifications (
tauri-plugin-notification), autostart (tauri-plugin-autostart+--hidden), global shortcut (tauri-plugin-global-shortcut), connect modes (smart/explicit;connect.rsstores settings in~/.dsh-app/settings.json); the settings UI is injected into the official settings page ("Desktop" section). Design & integration record:docs/P1-design.md/docs/P1-integration-checklist.md - P2 (next) — more workbench surfaces via the plugin route: PTY terminal, Git Review, plugin marketplace
License
MIT © dsh-app contributors




