s3yf1337
dsh-desktop
Desktop profile for the DeepSeek Harness: a native Tauri window over the harness web surface — tray, single-instance, OS notifications, suggest-only updater, native dialogs, drag & drop, and an in-app settings tab.
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 14, 2026
- Updated
- Aug 15, 2026
Introduction
dsh-desktop
DeepSeek Harness in a native desktop window — built the way the harness itself is built: as a plugin, not a fork.
dsh-desktop is a DeepSeek Harness
profile that composes the standard bundles (dsh-base + dsh-web-app) with a
small plugin — this repo's dsh-desktop-shell — which opens the harness web
surface in a native Tauri window: custom title bar, tray icon, native
notifications, a real file-manager panel, and one-click updates.
The idea: desktop as a plugin
DeepSeek Harness is built on the principle that everything is a plugin: models, tools, sandboxes, session storage, the UI — even the agent loop itself. The desktop experience should follow the same rule.
This project adds a native window without forking or repackaging the harness. The profile is plain composition:
dsh --profile desktop → dsh-base + dsh-web-app + dsh-desktop-shell
That one decision buys a lot:
- Always in sync. The harness keeps updating; so do you. There is no fork to rebase and no bundled copy to refresh — upstream releases land in your profile exactly the way they always do.
- Composable. The shell is one row in your profile's bundle list. Keep your other bundles, swap the web app, add plugins — the desktop layer stays a layer, not a replacement.
- Small. The native client is a Tauri binary, not a bundled browser plus a full runtime. Your dsh stays your dsh.
- Honest trade-off. The plugin approach assumes you already run
dsh. If you want a single installer with zero prerequisites, a standalone app that bundles its own runtime is the better fit. If you want the desktop to be part of your harness — same config, same workspaces, same plugins — this is the one that fits.
Features
- Native window with an app icon in the dock/taskbar and a custom title
bar (drag region, minimize/maximize/close) drawn by the web surface,
matching the app theme on every platform. The window title follows the
chat open in the UI right now (
DeepSeek Harness — <chat title>), not the last started agent. - Explorer panel — a real file manager. Browse any folder (not just the
workspace) with breadcrumbs, back/forward, name filter and recursive
search, sort by name/size/date. Right-click or keyboard (F2 rename, Del to
trash, arrows) to create, rename, copy, cut, paste, delete, open
externally. Files changed or created since your last look are marked live
(auto-refresh). A Preview tab renders markdown with the app's own
renderer (headings, tables, task lists, syntax-highlighted code with a
copy button, math — and relative images resolved from the local disk),
opens local
.htmlpages in a sandboxed frame, shows images (click to zoom, dimensions), and falls back to a hex dump for binary files. A URL bar in the preview opens any web page (external links land in the system browser). Previews re-render automatically when the file changes on disk (text 1 MiB / images 8 MiB caps). - Wired into the harness. Right-click a file → Send path to agent inserts its workspace-relative path into the composer; images can be attached to a message; the workspace picker (hero + sidebar + settings) is the panel in "choose a folder" mode instead of an OS dialog.
- Tray + close-to-tray. Closing the window hides it; running agents keep working.
- Native notifications on agent finish, error, and question events.
- One-click updates. Download, apply, restart. Nothing is applied automatically; background checks are opt-in (off by default).
- Workspace selection via the OS folder dialog, or drag-and-drop a folder into the window.
- A
dsh-desktoptab inside the harness Settings for desktop preferences.
Screenshot

DeepSeek Harness in a native window: the harness web surface with the custom title bar and the explorer panel.
Install
Requires the dsh CLI. Rust is needed only for the first build from
source — prebuilt client binaries skip it.
Pre-built installers per platform — .deb (Linux), .dmg (macOS), NSIS
.exe (Windows) — are published on the
releases page. One
installer places the client binary and registers an app-menu entry; the
first launch bootstraps the desktop profile into dsh and opens the window.
From source (Linux/macOS dev path):
git clone https://github.com/s3yf1337/dsh-desktop && cd dsh-desktop
./install.sh # full bootstrap (builds the client if needed)
./install.sh --no-build # use an existing client binary, never build
./install.sh --rebuild # force a client rebuild
dsh-desktop
The client binary itself is also a plugin installer:
dsh-desktop-shell install # bootstrap the profile + install client/launcher
dsh-desktop-shell install --prefix /usr # OS-package layout (menus under /usr/share)
dsh-desktop-shell # install, then boot the profile
dsh-desktop-shell --version
Runs on Linux, macOS, and Windows.
Technical details (for contributors)
How it works
dsh --profile desktop (or the `dsh-desktop` menu launcher)
└─ dsh-base + dsh-web-app the whole web surface: server, /api, SPA
└─ dsh-desktop-shell this repo's plugin bundle: after the server
binds, spawns dsh-desktop-shell <url> and watches it
└─ dsh-desktop-shell (native client, src-tauri/)
opens a native WebView on http://127.0.0.1:<port>
window closed → exit 0 → plugin shuts the harness down
dsh-desktop is a profile for the DeepSeek Harness, composed from the
standard bundles (dsh-base + dsh-web-app) plus this repo's
dsh-desktop-shell plugin. The plugin spawns the native Tauri client on the
served loopback URL; the WebView loads the exact same 127.0.0.1 origin a
browser would, so the whole SPA works unchanged and same-origin. The client
exposes window.__TAURI__ to that origin (withGlobalTauri), and the plugin
pipes agent-lifecycle notifications to the client over a stdin control
channel ({"event":"notify", ...} JSON lines). The window title follows the
chat open in the UI right now: the browser half reads the active session
from the harness's sessions service and mirrors it into the native window
and the custom title bar.
Install options
One installer per platform (from the releases
page): .deb on Linux, .dmg on macOS, .exe (NSIS) on Windows. The
installer places the client binary and registers an app-menu entry; the first
launch of the installed app bootstraps the plugin profile into dsh and opens
the window. The client binary is also a plugin installer:
dsh-desktop-shell install # bootstrap the profile + install client/launcher
dsh-desktop-shell install --prefix /usr # OS-package layout (menus under /usr/share)
dsh-desktop-shell # same as install, then boot the profile
dsh-desktop-shell --version
From source (Linux/macOS dev path), install.sh works as before:
./install.sh # full bootstrap (builds the client if needed)
./install.sh --no-build # use an existing client binary, never build
./install.sh --rebuild # force a client rebuild
install.sh creates $DSH_HOME/profiles/desktop (bundle copied and linked,
no pnpm/registry needed), builds the client if missing, installs
dsh-desktop-shell + the dsh-desktop launcher to ~/.local/bin, installs
the icon into the hicolor theme, and registers a desktop menu entry.
Idempotent: re-running refreshes the bundle copy and never touches your
profile's cordis.patch.yml user layer. The binary's own install mode is
the cross-platform equivalent (it embeds the bundle, so one artifact installs
everything).
Release artifacts (CI-built)
Every v* tag builds, bundles, and publishes per platform:
- Installers —
DeepSeek Harness_<tag>_amd64.deb(Linux),.dmg+.app(macOS), NSIS.exe(Windows) - Update tarballs —
dsh-desktop-<tag>-linux-x86_64.tar.gz,-macos-aarch64.tar.gz,-windows-x86_64.tar.gz(client binary +bundle/)
The in-app one-click update downloads its platform tarball, swaps the client binary, refreshes the plugin bundle, and restarts. Nothing is ever applied automatically; background checks are opt-in (off by default).
Configuration
The dsh-desktop launcher resolves the dsh CLI: $DSH_DESKTOP_DSH →
$DSH_BIN → dsh on PATH. DSH_HOME is inherited (defaults to
$HOME/.dsh).
The native client honors:
DSH_DESKTOP_NO_SINGLE_INSTANCE=1— skip the single-instance guard so a second harness can run side by side (development/debugging)DSH_DESKTOP_BIN— an explicit client binary path
Client binary resolution in the bundle plugin: config.bin → DSH_DESKTOP_BIN
→ $DSH_HOME/bin/dsh-desktop-shell → dsh-desktop-shell on PATH →
~/.local/bin/dsh-desktop-shell. With no binary found the harness still
serves the web UI (degrades to browser use).
The window is frameless; the web surface draws the title bar (drag region, minimize/maximize/close, resize edges) and the right-hand explorer panel (Files/Preview tabs). The shell exits with code 0 when the user is done and code 11 after a one-click update (the plugin relaunches the profile).
Layout
bundle/ the dsh-desktop-shell plugin package (bundle contract)
cordis.patch.yml inserts the desktop-shell row
lib/index.js spawn/watcher plugin (webServer, appExit, stdin control,
loopback-only /dshd-file route: local files for the
preview panel — markdown images, .html pages, assets)
lib/client.js browser half: title bar, explorer panel (markdown /
web / image / hexdump previews), settings tab
dist/index.html loading page shown while the WebView boots
dsh-desktop launcher wrapper: exec dsh --profile desktop
install.sh one-command bootstrap (profile + client + icons + menu entry)
src-tauri/ the native render client (the actual app)
src/main.rs
src/lib.rs arg dispatch (url | install | no-arg), frameless window,
tray, close-to-tray, single-instance, stdin control
src/install.rs plugin installer mode (embedded bundle, cross-platform)
src/fs.rs explorer commands (list dir, read file, stat, hexdump,
home, parent)
src/commands.rs desktop_* commands the settings tab invokes
src/settings.rs persisted desktop preferences (dsh-desktop.json)
src/tray.rs tray icon + menu (show/hide, updates, quit)
src/update.rs update orchestration (check, emit, notify, apply, restart)
src/updater.rs GitHub releases API client (assets, suggest + one-click)
src/log.rs file + stderr logging (dsh-desktop.log)
Cargo.toml
tauri.conf.json
capabilities/default.json
test/client-smoke.mjs renders client.js (title bar module + explorer + settings)
and exercises the preview helpers (markdown image
rewrite, TOC, URL normalization, path resolution)
The installed profile lives at $DSH_HOME/profiles/desktop/:
profiles/desktop/
package.json dsh.profile.bundles: base + web-app + dsh-desktop-shell
cordis.patch.yml your patch layer
packages/dsh-desktop-shell/ a copy of bundle/ (refreshed by install.sh)