DeepSeek Harness automatically opens browser plugins and includes a built-in WebView2 program to achieve a lightweight desktop experience.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-auto-open-web
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:jinsiyu/dsh-auto-open-web
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
A persistent plugin for the dsh web profile that automatically opens the DSH Web GUI in an app-style
window (or browser tab) on profile start, with a configuration form (manually maintained
browser path, etc.). On dsh ≥ 0.1.5 that entry point is the bundle's detail page on the
Plugins page; on rc.7–0.1.4 it is the Settings → Plugin configuration card.
Behavior
On startup (after the HTTP service binds and the actual listening port is known), the window type is
selected by windowKind:
- WebView2 host (
windowKind: webview2, default, Windows only): launches the bundledDshAppWindow.exe(WinForms + WebView2, own process, no tab/address bar), loading the GUI root address directly (no iframe, no wrapper page, no injected scripts). Taskbar/window icon = DSH icon (the window is owned by the host process, which setsForm.Icondirectly, independent of browser taskbar identity rules). Exits with DSH (the host watches the parent process PID). Remembers window size/position/maximized state (%LOCALAPPDATA%\DeepSeekHarness\window-state.json, saved on close and restored on start; falls back to centering when the display layout changes). - Browser app window (
windowKind: browser): a dedicated Edge/Chrome instance via--app(--user-data-dir=~/.dsh/<browser>-app-profile, isolated process tree and storage, shares no processes/Cookies/cache with the normal browser;--no-first-runskips the first-run welcome page). Exits with DSH (including force-kill): the browser instance is placed into a Job Object (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, koffi-drivenJOBOBJECT_EXTENDED_LIMIT_INFORMATIONstructure, 144 bytes verified); whether DSH exits normally or is force-killed (taskkill /F, crash, shutdown, etc.), the Windows kernel terminates every process in the job when its last handle closes — the whole dedicated instance process tree dies with it, with no reliance on any exit event. Two extra safety nets: on normal DSH exit aprocess 'exit'handler kills the dedicated instance process tree (matching only our own user-data-dir, never the normal browser); instances left behind by a force-kill are cleaned up before the next launch. - If the selected type is unavailable (host missing / browser not found / non-Windows, etc.) →
falls back to the official default-browser handoff — the URL is given to the OS default
browser (plain tab), so the user can always reach the GUI. The implementation mirrors exactly
how the DSH core (web-app bundle) opens the page at startup: it prefers the
openpackage shipped with the DSH deployment (win32 = PowerShell Start, darwin =open, linux =xdg-open); when the package is unavailable it falls back to a native platform launch (win32 =cmd /c start, darwin =open, linux =xdg-open).appWindow: falsebehaves exactly like the official core: the GUI is opened in the system default browser (plain tab, officialopenmethod). --no-open/ SSH sessions (official identical suppression):dsh web --no-open(webStartup.openBrowser === false) or an SSH session (SSH_CONNECTION/SSH_TTYenvironment variables, the same source as the officiallaunchedThroughSsh) opens nothing — the plugin reads the same source as the official core (thewebStartupservice provided by web-startup) and suppresses opening the same way.
The port comes from the real listening value of the webServer service (--port overrides and
--port 0 both work). No waiting needed: the plugin declares webServer as a hard dependency
(inject), so Cordis only activates it after the webServer plugin's Service.init() completes
(HTTP socket bound, port written) — the port is directly available in apply.
Both modes close with DSH: the webview2 host watches the parent process; the
browser dedicated instance is ended by the Job Object (also effective on force-kill) plus exit
cleanup.
Relationship with DSH's core browser handoff: the DSH core (web-app bundle) opens the GUI in the system default browser at startup by default (
openBrowser: true— a plain tab/window, not an app window). Installing this plugin flipsweb-runtime.openBrowsertofalsevia the plugin's bundle patch, so the opening behavior is fully owned by the plugin: withappWindow: truethe app-style window opens and no ordinary browser page pops up; withappWindow: falsethe plugin performs the same default-browser handoff as the official core (open package → native platform launch), matching the no-plugin behavior. Withdsh web --no-open(or in an SSH session) the plugin, like the official core, opens nothing. Uninstalling the plugin restores the official default.
WebView2 host requirements (webview2 mode only)
- Windows 10 1803+ / Windows 11 / Windows Server 2016+ (Win7/8.1 reached end of support in 2023-01, see Microsoft announcements)
- WebView2 Runtime (evergreen, usually preinstalled with Edge; verified with 151.x locally)
- No .NET 10 runtime required: since 0.1.15 the host targets .NET Framework 4.7.2,
built into Windows 10 1803+ / Windows 11 (4.8.x on Win11) — no .NET Core/10 runtime or
self-contained publish is needed. The build machine needs a .NET SDK and the .NET
Framework 4.x targeting packs (installed with VS/SDK; without them add the
Microsoft.NETFramework.ReferenceAssembliesNuGet package to the csproj). - DPI awareness (since 0.1.20): the host declares PerMonitorV2 (
host/app.manifestplus the WinFormsDpiAwarenesssection inApp.config). .NET Framework WinForms is DPI-unaware by default, so on 125%/150% scaled displays Windows renders the window at 96 DPI and bitmap-stretches it (DPI virtualization) → blurry text and web content. Declaring awareness renders natively at the monitor's real DPI, keeping text crisp.
Configuration
Two equivalent ways:
Settings form (recommended) — two supported version lines; the plugin registers for both and whichever exists wins:
- Newest version (dsh ≥ 0.1.6-alpha, incl. 0.1.7-alpha.1): Plugins page →
dsh-auto-open-web→ this plugin's row → Configure. The form opens per row (slotplugins.row.config, key<package name>#<row id>=dsh-auto-open-web#auto-open-web); the page supplies the data (form = { state, mutate }— the host-projected row Config snapshot plus atomic writes) and the plugin only draws the controls. Only Save is offered — leaving the page drops staged edits. - Latest rc line (0.1.5-rc.x): Settings → Plugin configuration → the "自动打开网页"
collapsible card (slot
settings.plugin.item, keyed by settings namespace). Data goes through the host'ssettings.registerplus the clientsettingsScope.
The two lines' client services do not coexist (new
configForms↔ rc-linesettingsScope), so the plugin reads both lazily and declares only the shared services ininject(slots/locale/connection/remote) — a hard inject would leave the plugin pending forever on the other line and the settings UI would never appear. Earlier versions (0.1.0-rc., 0.1.1-rc., 0.1.2-*, 0.1.3-alpha, 0.1.5-alpha, 0.1.6-alpha.1) are no longer guaranteed.Both entry points edit
appWindow(independent app window),windowKind(WebView2 host / browser app window),browserPath(browser executable, with a native "Browse" file dialog; located below the window-type field and enabled only when "Browser app window" is selected),exitOnWindowClose(exit DSH when the window closes, off by default). After saving, values take precedence over row configuration (on the newest version they land in that row's user layer; on the rc line in theauto-open-websettings namespace); once saved, settings take precedence over row configuration. The host keeps only the "Browse" / "Test" helper routes (capabilities the official channel cannot cover).- Newest version (dsh ≥ 0.1.6-alpha, incl. 0.1.7-alpha.1): Plugins page →
Row configuration (
cordis.patch.yml): acts as the startup seed, effective until the settings card is saved.
| Field | Default | Description |
|---|---|---|
appWindow |
true |
Automatically open the independent app window on start; false matches the official core — the GUI opens in the system default browser (plain tab, official open method) |
windowKind |
webview2 |
webview2 = WebView2 host (own process, DSH taskbar icon, exits with DSH); browser = dedicated --app browser instance. If the selected type is unavailable, it falls back to the default-browser handoff (official open method, plain tab) |
exitOnWindowClose |
false |
(Experimental) Exit DSH when the auto-opened window closes (off by default; only effective while appWindow is on). Triggered only when the window process exits normally (user closes the window) → process.exit(0); startup failures/crashes/force-kills (non-zero exit code) do not trigger, preventing accidental exits. Takes effect immediately in the current session after saving (the exit listener is always registered; behavior is driven by a live flag), no restart needed |
browserPath |
'' |
Manual browser executable path (single entry, e.g. C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe; used only in browser mode), preferred over the built-in candidates Edge → Chrome; a non-existent path is skipped with a warning. The "Browse" button on the card opens a native file dialog: same mechanism as the official workspace directory picker (child process + koffi-driven IFileOpenDialog; the dialog is the child's first window and is automatically brought to front; no PowerShell). The "Test" button actually launches a dedicated --app test instance (separate user-data-dir ~/.dsh/<browser>-test-profile, never pollutes the real instance): after confirming the browser main process stays alive it reports success, then automatically ends that test process tree after a few seconds of display (exact pid, never touches the real instance; the test instance is also placed in the Job Object when available as an exit safety net); the test uses the currently typed path (works even when unsaved), and failures show the reason |
browserPath row configuration example
Override the row's config by id in ~/.dsh/profiles/web/cordis.patch.yml (the override replaces the
whole config; fields not listed fall back to defaults):
- id: auto-open-web
config:
browserPath: 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
Packaging and installation
This package is a bundle: an npm package carrying a configuration layer — dsh.bundle in
package.json declares the patch file (cordis.patch.yml), and a profile activates the plugin row
by package name when installed. Published to the npm registry (dsh-auto-open-web@0.1.5) and
GitHub (https://github.com/jinsiyu/dsh-auto-open-web, main branch).
Packaging
cd dsh-auto-open-web
pnpm pack # the prepack hook compiles the WebView2 host first (dotnet publish), producing dsh-auto-open-web-0.1.5.tgz
Installation (pick one)
Option 1: source checkout link (development; changes take effect immediately)
# absolute path to avoid pnpm self-linking
dsh plugin --profile web add C:\path\to\dsh-auto-open-web
Option 2: tarball (published artifact, recommended for delivery; no build permission needed)
dsh plugin --profile web add ./dsh-auto-open-web-0.1.5.tgz
Option 3: npm registry (after publishing)
dsh plugin --profile web add dsh-auto-open-web
Option 4: GitHub source
dsh plugin --profile web add github:jinsiyu/dsh-auto-open-web#main
Uninstall
dsh plugin --profile web remove dsh-auto-open-web # removes the dependency and its configuration layer together
Effect and layer order
After installation: pnpm adds the package to profiles/web/node_modules, and dsh appends
dsh-auto-open-web to dsh.profile.bundles; at startup the bundle's cordis.patch.yml inserts the
plugin row (name: auto-open-web, resolved by package name). After restarting dsh web, the
configuration form shows up at the matching entry point (dsh ≥ 0.1.5: the dsh-auto-open-web
bundle's detail page on the Plugins page; earlier versions: the Settings → Plugin configuration
card). The client bundle is scanned into the browser manifest at startup via the modules line,
per the dsh.client declaration; on the client the plugin registers into both
plugins.bundle.config (new) and settings.plugin.item (old), and the slot machinery decides
which one takes effect (a slot that does not exist stays pending — no error, no interference).
The effective configuration is composed layer by layer in this order (later layers win per row,
replacing the whole row's config rather than deep-merging): each bundle's patch (in bundles list
order) → the profile's own cordis.patch.yml → the global $DSH_HOME/cordis.patch.yml → the
--patch overlay. Users can override this package's row in their own profile's cordis.patch.yml
without touching the package.
Notes
- Zero dependencies: every runtime dependency is provided by the DSH deployment and
declared as an optional peer (no install warnings):
@deepseek-ai/dsh(the host; declares the compatibility range>=0.1.5-rc.1 <0.2.0— covering the latest rc line (0.1.5-rc.x) and the newest version (≥0.1.6-alpha, incl. 0.1.7-alpha.1); older 0.1.0-rc./0.1.1-rc./0.1.2-*/0.1.3-alpha/0.1.5-alpha releases are no longer guaranteed. The snapshot store uses@deepseek-ai/dsh-client-storeonly — the rc.8-eradsh-client-runtimefallback was removed; the client registers the newest version's row slot (plugins.row.config) and the rc line's settings slot (settings.plugin.item); no runtime version check is performed)@deepseek-ai/schemastery(config schema validator; resolved at runtime: normal import first, then the DSH deployment copy under the Windows global npm layout)koffi(Windows only: Job Object / process verification / native file dialog; same runtime deployment-copy resolution, failure only degrades) So no platform ever hits build-script blocking — HarmonyOS and other environments without koffi prebuilds install out of the box; posix platforms use the posix fallback adapter (browser mode works; webview2 / native dialog unavailable), and the platform adapter is loaded conditionally so win32.js is never evaluated on posix.
- This package does not depend on
@deepseek-ai/cordis(zero code references; the plugin identity comes from thedsh.bundle/dsh.clientfields, and Cordis is provided by the DSH deployment at runtime), so installation produces no peer warnings. - The npm package already contains the compiled WebView2 host (built by the prepack hook before
publishing); the GitHub
mainbranch and source-checkout installs do not includehost-publish/(build artifacts are .gitignore'd): for webview2 mode, runpnpm run build:hostinsidenode_modules/dsh-auto-open-webfirst (requires the .NET SDK); browser mode needs no build. - If installing by editing
package.jsonmanually (not via thedsh plugincommand), you must add both thedependenciesentry anddsh.profile.bundles; when using a localfile:dependency,dsh webnormalizesfile:to^0.1.5at startup, which does not affect runtime.
Icons
- GUI page icon: the GUI ships its own
/favicon.svg(same as index.html). - Taskbar/window icon (WebView2 host): the host process sets
Form.Icondirectly to the plugin-generated DSH .ico (~/.dsh/auto-open-web-icon.ico), independent of browser taskbar identity rules. The .ico is built by fetching the localfavicon.svgand rasterizing it with sharp (bundled with the deployment, resolved upward at runtime, not declared as a dependency) into 16/32/48/64/128/256 PNGs. - Fixed-icon policy (since 0.1.14): once written, the .ico is cached and reused — later
starts return the existing non-empty cache directly (no favicon fetch / rasterization, so the
icon cannot vanish on a transient favicon/sharp failure, and starts are faster); it is
generated only when the cache is missing. Extra safety net:
host/icon.ico(same source as the cache) is embedded into the host exe via<ApplicationIcon>, so even with a missing cache the window/taskbar shows the DSH icon instead of the default one.
Platform support
- Windows:
windowKind: webview2(default, DSH taskbar icon) orwindowKind: browser(dedicated--appinstance); falls back to the default-browser handoff (official open method, plain tab) if the selected type is unavailable - macOS/Linux:
webview2mode is unavailable (falls back to the default-browser handoff);browsermode is untested (dedicated--appinstance)
Edge cases
- Normal restart: in webview2 mode the old host window exits with the old DSH process; the new DSH opens a new host window
browsermode: after a restart the old window stays as-is (needs a manual refresh; may briefly coexist with the new window); when DSH is force-killed (taskkill /F, crash), the dedicated instance is ended by the Job Object without leftovers- Plugin removed: no injected code, no leftover routes, zero residual impact
Links
More in this category
Tencent/WeKnora#dsh-weknora★ 31531
Four read-only tools over a WeKnora knowledge base: list knowledge bases, hybrid passage search, reassemble one document's chunks in order, and WeKnora's own cited RAG or ReAct-agent answer with a resumable session id.
superdesigndev/treg★ 3949
Tool catalog for agents: search ~2,600 external endpoints (SEO and SERP, backlinks, social, people and company enrichment, ad libraries, scraping) by the task you want done, read each one's parameters and per-call price, then call it with the credential injected server-side. Ships the skill plus an MCP row that stays disabled until TREG_TOKEN is set.
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1130
Tencent CloudBase backend for DeepSeek Harness — scaffold and deploy full-stack apps from chat, render query results as table cards with paging, sorting and CSV export, preview a deployment on its domain, and call the CloudBase MCP toolset (`mcp__cloudbase__*`) with device-code login.
gitroomhq/postiz-agent#dsh-postiz★ 499
Connects DeepSeek Harness to Postiz over MCP: list connected social media channels, fetch per-platform posting rules, and schedule, draft, or publish posts to X, LinkedIn, Instagram, Facebook, Threads, TikTok, YouTube, Reddit, Bluesky, Mastodon, Discord, Slack, Telegram and more; adds a postiz workflow skill.
EthanYoQ/Invoice-Downloader#dsh-invoice-downloader★ 477
Local IMAP invoice download, OCR, archive, and Excel reimbursement summaries for DeepSeek Harness.
anysearch-team/anysearch-dsh★ 441
AnySearch-powered real-time web and vertical search provider for DeepSeek Harness.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.