Windows boot autostart and one-click restart for the DSH service, from inside DSH: a resident supervisor that outlives the host, so a failed restart cannot leave DSH down; DSH spawned attached to a hidden console the supervisor owns, so no console window appears; plus a restart button, the current tokenised access URL and an optional post-start hook.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Mandarin715/dsh-autostart
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
English | 中文
A Windows-only DeepSeek Harness plugin: enable "start the DSH service at boot" and restart that service from the settings page, one click each. No console window at any point.
⚠️ Disclaimer (read first)
Verify your environment before installing. The author is not liable for lost conversation history, interrupted tasks, or damaged data.
Restarting kills the DSH host process that runs your conversations and agent turns:
- Restarting while an agent is mid-turn → that turn is hard-interrupted and its result may never be written to disk
- A conversation not yet flushed to
~/.dsh/sessions/→ that history may be lost and is not recoverable - Tasks running in parallel sessions are interrupted too
Before you use it: (1) verify the environment yourself (Windows version, Node, DSH version, whether security software blocks registry writes); (2) make sure no important task is running before you restart; (3) back up ~/.dsh/sessions/ for important conversations; (4) decide for yourself whether to enable boot autostart (it writes to HKCU\...\Run).
The software is provided "as is" (MIT License, no warranty of any kind).
Requirements
- Windows 10 / 11 (
Win32_Process.Createmust work through PowerShell — the restart helper is deliberately created by the WMI service, so that it is not killed together with the host) - Node.js ≥ 20 (shipped with DSH)
- DeepSeek Harness ≥
0.1.0-rc.6(tested on0.1.2-rc.1; the job-object behaviour the restart depends on was measured on0.1.5-rc.1) - A writable
HKCU\...\Runfor autostart — security software that blocks registry writes makes "enable" fail
Environment and restart
The restart helper is created by the WMI service, not by DSH directly. DSH runs its subprocesses inside a Windows Job Object created kill-on-close, so a merely "detached" helper is killed the instant DSH exits — leaving DSH down. Having WMI create it is what lets it outlive the host.
One consequence: a process created that way does not inherit your environment. So:
- the helper is told where
config.jsonlives explicitly (--config <absolute path>), instead of re-deriving the DSH home fromDSH_HOME(which would be missing); - the restart re-asserts
DSH_HOMEfrom thedshHomecaptured inconfig.json.
Other environment variables (a custom PATH, extra variables DSH reads) are not carried over
to the restarted instance. If your DSH setup depends on environment variables, keep that in mind,
and prefer an absolute command.execPath.
Install
dsh plugin --profile web add github:Mandarin715/dsh-autostart
Restart DSH, then open Settings → General and scroll to the bottom to find this plugin's card.
Usage
| Control | What it does |
|---|---|
| Service status | Probes the port live; shows running / stopped |
| Boot autostart toggle | When enabled, writes ~/.dsh/dsh-autostart/config.json, generates bootstrap.vbs, and adds the DSH autostart entry under HKCU\...\Run |
| Current access URL | The newest token-bearing URL parsed out of the captured startup output; one-click copy |
| Restart service | Restarts after a confirmation; DSH is back within seconds |
| Hook script | Optional. Run once the service is up, to start your own dependent processes |
Cannot open the page at all? This card only exists while DSH is running — see If the service will not start below.
Configuration
In the profile's cordis.patch.yml:
- id: dsh-autostart
name: dsh-autostart
config:
hookScript: '' # optional, absolute path to a script run after the service starts
dshPort: 3080
exitDelayMs: 800
waitForExitMs: 30000
startTimeoutMs: 30000
openBrowserOnBoot: false # true = open the browser on boot
blockWhenAgentsRunning: false # true = refuse to restart while an agent is running
allowedHosts: [] # for reverse-proxy access, add your domain (must be opted in), e.g. ['derp.example.com']
allowedHostsis opt-in — you must add the entry yourself. The default is an empty array, meaning no non-loopback Host is trusted. If you reach DSH through a reverse proxy (for example frp + auth-proxy, which forwards the browser's original Host), the request's Host is your public domain rather than127.0.0.1, so the write buttons (enable / disable autostart, restart service) are refused with 403. Add your domain toallowedHoststo make those buttons work; the same-origin check (Origin must equal Host exactly) still applies to those entries — see the accepted forms below.
Accepted allowedHosts forms: a bare host, or host:port — for example ['derp.example.com'] or
['derp.example.com:8443']. Do not include a scheme or a path (https://derp.example.com/ is wrong).
Because a browser reaching https://derp.example.com sends no port at all, the local dshPort check is skipped for
allow-listed authorities — the entry itself is the explicit opt-in, and the Origin/Host match still has to hold.
Loopback keeps the strict port check.
Do config changes require re-enabling autostart? Yes — but not because of dispose.
hookScript,dshPort,waitForExitMsandstartTimeoutMsare snapshotted intoconfig.jsonwhen you click Enable, and the helper readsconfig.json, not the plugin's live config. So after changing them you must open the settings card and enable autostart again (re-enabling is idempotent). Measured on a real install: changinghookScriptand only restarting the service left the old value inconfig.json, so the hook never ran.allowedHostsis different — it only affects the plugin's route guard and takes effect on reload.The registry entry does not disappear because you edited the config. The plugin removes
DSH autostartonly when it is genuinely uninstalled (evidence: its ownservice.jsis gone); when DSH tears the plugin tree down for a reload or a failed load, the entry is kept.
Coexisting with an autostart entry you already have (important)
This plugin manages DSH only. If you already have your own boot entries (for example DSH Web, DSH frpc,
DSH authproxy under HKCU\...\Run), then after enabling this plugin's autostart two entries will both try to
start DSH at login.
- ✅ They do not overwrite each other: this plugin writes and deletes only its own
DSH autostartvalue and never touches yours (measured: after enabling, the user's other entries were untouched). - ⚠️ But they do duplicate work: both dedupe via "skip if the port is already listening", so you still end up with one DSH — yet there is a narrow race: if both run and both probe before either binds the port, both will try to launch, and one will fail because the port is taken (harmless, but it leaves a failure in the log and possibly a stray process).
Option A: keep only this plugin (simple)
Delete your own DSH entry:
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "DSH Web" /f
Then click Enable in the settings card.
⚠️ Do not also delete
DSH frpc/DSH authproxy— this plugin does not manage frpc or auth-proxy. If phone access depends on them, deleting those entries loses their autostart. Use Option B to merge instead.
Option B: merge into "one autostart + one hook" (least to maintain)
The hook runs at boot and after every restart, so put "make sure my other processes are running" in it and let this plugin be your only autostart entry.
Write a hook, for example
~/.dsh/hooks/after-service-up.ps1:# once the service is up, make sure the other processes run (adjust the paths) & "$env:USERPROFILE\.dsh\scripts\start-frpc.ps1" & "$env:USERPROFILE\.dsh\scripts\start-authproxy.ps1"Point the plugin at it in the profile's
cordis.patch.yml:- id: dsh-autostart name: dsh-autostart config: hookScript: 'C:\Users\<you>\.dsh\hooks\after-service-up.ps1'Click Enable again in the settings card (
hookScriptis snapshotted intoconfig.jsonwhen you enable), then deleteDSH Web/DSH frpc/DSH authproxyand keep only this plugin'sDSH autostart.
A failing hook does not block DSH (it is only logged), so its steps may fail independently. To check whether it ran, look for
hook exited code=…in~/.dsh/dsh-autostart/service.log.
| Your existing entry | Option A | Option B |
|---|---|---|
DSH Web (starts DSH) |
delete | delete |
DSH frpc / DSH authproxy |
keep | delete; the hook takes over |
Generated files
~/.dsh/dsh-autostart/
├── config.json # the real launch command, read by service.js
├── bootstrap.vbs # boot entry point (wscript, no window)
├── dsh-web-server.log # DSH stdout (contains the access URL)
├── dsh-web-server.err.log
└── service.log # helper log; look here first when debugging
If the service will not start (recovery)
The card lives inside DSH's page — so when DSH is down you cannot open the card. Recovery therefore has to be command-line. Work down this list.
1) Read the logs first
~/.dsh/dsh-autostart/service.log # the helper's log: start here
~/.dsh/dsh-autostart/dsh-web-server.err.log # DSH's own errors
Three common shapes:
WARN port 3080 did not come up in time→ DSH was launched but never listened; look atdsh-web-server.err.loghook not found:/hook exited code=…→ a hook problem; it does not block DSHcannot read config→config.jsonis missing or corrupt
2) The general fix: run the boot entry point once by hand
This is exactly "run boot autostart right now". It is idempotent (it skips when the port is already listening) and it opens no window:
wscript.exe "$env:USERPROFILE\.dsh\dsh-autostart\bootstrap.vbs"
It runs <node> <service.js> start --config <config.json>, starts DSH hidden, and writes DSH's stdout to
~/.dsh/dsh-autostart/dsh-web-server.log — on success a fresh token URL appears there.
3) If config.json does not exist at all
Autostart was never enabled. Start DSH the way you normally do, then enable autostart in the settings page.
4) Your own launcher script works too — with two rules
The rules are start it hidden / in the background, and never let a console window be the service's host:
- ✅
Start-Process … -WindowStyle Hidden, or awscriptVBS, so DSH becomes a background process - ❌ Do not use a foreground console launch such as
npx @deepseek-ai/dsh web; and never "grab the tokenised address, then close that window" — the window is DSH's console, and closing it makes Windows terminate DSH, which kills the link too. You then get "connection refused" rather than 401, and pasting it again will not help.
On the author's machine this step is
~/.dsh/scripts/start-dsh-web.ps1(it launches withStart-Process -WindowStyle Hiddenand captures stdout into~/.dsh/logs/dsh-web-server.log). That is the author's local script, not part of this plugin — substitute your own equivalent, or just use step 2.
5) Do not confuse the two failure modes
| What you see | What it means | What to do |
|---|---|---|
| 401 Unauthorized | the service is running; this browser just has no session | open the tokenised address from "access URL" once; do not restart |
| This site can't be reached / connection refused | the service is not running | work through 1)–4) above |
Three facts about that tokenised address: (1) it is local-only (127.0.0.1; the phone uses the domain plus the
password, and the reverse proxy exchanges the token for you); (2) the session cookie it grants lasts 30 days and
survives closing the browser and restarting DSH; (3) but the token itself is per DSH process and dies on every
restart — so use the current one (the card always shows the latest); bookmarking one for later does not work.
6) How you know recovery worked
- port 3080 is LISTENING
service.logcontainsport 3080 is up- the card's "service" line says running
7) If you recently upgraded or moved DSH
config.json stores an absolute path captured at the time (it may contain an npx cache hash directory such as
…\_npx\<hash>\node_modules\@deepseek-ai\dsh\lib\bin.js). After an upgrade or a move that path can go stale, and
autostart then fails silently (nothing happens at login). Open the settings card and click Enable again so the
current command is captured.
Uninstall
Disable boot autostart in the settings page first (this removes the registry entry)
This step is required, not optional. Two reasons: (1) the registry entry points at
~/.dsh/dsh-autostart/bootstrap.vbs, and that file andconfig.jsonlive outside the plugin directory, so removing the plugin does not delete them; (2)pnpm removekeeps thenode_modules/dsh-autostartsymlink, so this plugin'sservice.jsis still reachable — and that reachability is exactly the plugin's cleanup test. So uninstalling without disabling first leaves a dead entry (it runs once at login and fails silently). DeletingDSH autostartfromHKCU\...\Runby hand afterwards works too.Note: Settings → Plugins has no uninstall button for this plugin (that page only manages plugins installed from the markets), so step 2's command line is the normal path.
Remove the plugin:
dsh plugin --profile web remove dsh-autostartTo clean up completely, delete
~/.dsh/dsh-autostart/by hand
Why it is built this way
- Why
wscript.exeinstead ofpowershell -WindowStyle Hidden: the latter is unreliable for long-running scripts and leaves an empty console window that cannot be closed. - Why waiting uses conditional polling instead of a fixed
Start-Sleep: a fixed wait once made a single restart take over 80 seconds; conditional polling brought it down to a few seconds. - Why the port check uses a TCP connection instead of a
netstat/:portsubstring: substring matching also hitsTIME_WAITand client connections, so it reported "already running" when nothing had actually started. - Why the logic is Node rather than PowerShell: Chinese text in PowerShell scripts tends to hit encoding problems, and execution policy gets in the way.
- Why
--no-openis mandatory: DSH0.1.2-rc.1mints a new token on every start and prints the access URL to stdout; the plugin captures it into the log and shows it in the settings page, so opening a browser at boot is neither needed nor wanted.
Links
More in this category
yjh051108/dsh-routing-suite★ 7176
One repository, three parts: a runtime injector for DSH plugin packages (inject, hot-reload, unload, promote a dev staging tool to the front, route self-heal, plus a settings-page plugin manager that lists, unloads and drags folders in to internalize), a task-aware reasoning-mode router agent preset (router-standard / router-spec / router-react), and a graded two-level task protocol whose six tools (commit_star, lock_stage, revise_do, edit_plan, mark_task, redteam_verdict) pin task state to disk. The injector implementation ships in-tree, so the install carries its own behaviour rather than a dependency list.
strukto-ai/mirage#dsh★ 3626
Swaps the filesystem and bash providers for a mirage virtual workspace: file tools and shell commands run over mounted resources (RAM, S3, Redis, Slack, Gmail, Notion, Postgres) instead of the host disk, with per-mount read/write/exec modes, per-command sandbox routing (monty, pyodide, quickjs in process; docker, e2b, daytona remote), and installed CLIs (git, gh, slack, linear, ntn, gws, or one you register) as head words in the virtual terminal.
hust-open-atom-club/oh-dsh★ 312
Community distribution: TUI, desktop, and Web UI as one bundle with layered installation.
lire1131/dsh-undo-savepoint★ 154
Undo/redo & rollback system for DSH: every config change is auto-snapshotted; undo/redo/restore to any version from the WebUI or the offline CLI/GUI tools (works even when DSH fails to boot).
Fishquito7/dsh-skill-mcp-panel★ 124
Manages DSH skills and MCP servers from the web settings: skill cards with hot enable/disable, workspace scopes, groups, batch migration and drag-and-drop import, plus stdio/HTTP MCP CRUD with connection tests, secret redaction and the unified dsh-panel CLI.
kanneiren/dsh-network-settings★ 109
Visualize the DSH process network path on Windows or WSL with layered DNS/TCP/TLS/HTTP probes, detect stale proxy configuration, and apply snapshot-guarded repairs.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.