Introduction

In DSH conversations, when asking the model to start a dev server, a common problem arises: once the conversation ends or the session closes, the service is gone. The root cause lies in pwsh background jobs (jobs) being bound to the owner session scope; when the session or turn ends, dsh-jobs-local cancels the associated tasks—the service simply doesn’t survive to the next round.

dsh-launch addresses this issue by entrusting the service to an independent detached broker process for supervision, ensuring the service continues running even after the conversation ends, the session closes, or even when DSH itself restarts. Below is an introduction to its mechanism, features, and usage.

What is it

dsh-launch is a DSH service management plugin maintained by Khellendros97, licensed under MIT, currently version 0.2.0, and requires Node >= 20. The supervision mechanism references the launch daemon broker from omp.

The core idea consists of three steps:

  1. The service is launched by the detached broker process via “detached + stdio to disk”, where stdio is written directly to disk logs.
  2. The broker only performs supervision—log incrementing, PID liveness checks, readiness detection, crash backoff restart—and exits when idle.
  3. When DSH starts next time, the broker is relaunched, and running services are adopted based on their PIDs.

The plugin is released as a single package: the Service sidebar tab, broker, and model tools are all within the same package; better-sidebar only handles the tab hosting (injected via its extension API, no changes needed on the better-sidebar side).

Core Features

Model Tools

  • service_start: Start a long-running service. Required: name + command. Optional: cwd/title/logo/env/readyLog/readyPort/restart. Returns after waiting for readiness.
  • service_stop / service_restart / service_list / service_logs: Stop (kill entire tree) / Restart / List / Read log tail.

Readiness determination strips ANSI escapes first, then performs dual-stack (IPv4/IPv6) port probing.

Service tab (Sidebar)

The sidebar displays service cards with title, logo (optional, URL or image path), status badge, PID, uptime, and restart count. Supports Start/Stop/Restart/View Logs. The tab polls the plugin’s own fenced /launch/api route when visible.

When better-sidebar is not installed, the plugin runs in headless mode: tools are available, but there is no UI tab.

ctx.launch (cordis service)

Consumed by other plugins, providing ping / list / start / stop / restart / describe / logs.

Monitoring Mechanism

Each service maintains a state machine: starting → running → ready → stopping → exited/failed (enters restarting backoff when enabled and failed). Restart strategies are no / on-failure (default) / always. Backoff is exponential, ranging from 1s to 30s.

Communication between the host and broker uses Named Pipes NDJSON protocol + token authentication. Pipe names are hashed based on runtimeDir, preventing conflicts in multiple deployments.

There are two switches for readiness detection:

  • readyLog: Regular expression match on output, ANSI escapes stripped.
  • readyPort: TCP probe, probes 127.0.0.1 and ::1 simultaneously when host is unspecified.

start/restart wait for readiness with a default of 20s and a maximum of 60s. When adopting starting records after broker restart, it rescans the log tail for already-rolled readiness markers to avoid false positives.

On Windows, the command string is executed by the built-in node launcher (broker/launcher.cjs) via cmd.exe /d /c—detached cmd loses batch subprocess output, and the launcher mitigates this; whole tree stop uses taskkill /T.

Installation & Enablement

Prerequisites: DSH web environment; dsh-better-sidebar is an optional dependency (^0.11.0 || ^0.12.0), only needed for UI.

dsh plugin --profile web add dsh-launch

One command for installation + auto-mounting: the package’s cordis.patch.yml registers into dsh.profile.bundles. After installation, restart dsh web first, then hard refresh the browser (Cmd/Ctrl+Shift+R).

Configuration

The plugin row can optionally have config, containing three items:

- id: dsh-launch
  name: dsh-launch
  config:
    runtimeDir: '~/.dsh/tmp/dsh-launch'   # Runtime directory, default is same as left
    idleGraceMs: 15000                     # Exit grace period after no clients or presence
    maxLogBytes: 8388608                   # Single service log rotation threshold, 8MB

The runtime directory ~/.dsh/tmp/dsh-launch/ contains: broker.token, broker.pid (single instance lease), presence/*.json (DSH liveness markers), and daemons/<name>/ (metadata + logs, 8MB rotation).

Testing

npm test

Tests are divided into two parts: 15 broker smoke tests (start, readiness with ANSI and IPv6, logs, stop, restart, persistence, adoption after killing broker, adoption tail rescan) and 13 wiring tests (service provision / tool registration / presence / real broker round trip / fenced route envelope / fence rejection / client contract).

Security Notes

  • Services run as the same user running DSH, outside any sandbox—this is a prerequisite for service survival; services are equivalent to processes started by the user in a terminal.
  • /launch/api and /launch/service-logo are all passed through the Host header trusted fence (loopback or trustedHosts); the broker pipe binds only to localhost (Named Pipe + token).
  • Plugin uninstallation (HMR/Disable) will not stop the service or broker; the broker exits itself after 15s of idling with no presence, while the service continues running.

Limitations

  • Service names must be globally unique (single broker scope for the entire machine).
  • No PTY / No stdin: For interactive processes, please use the better-sidebar terminal.
  • In the broker death window (DSH not running and broker already exited), crashed services will not auto-restart, but the detached service itself remains unaffected.

Suitable Scenarios & Notes

Suitable scenarios: processes like dev servers, watchers, mock APIs, and workers that need to survive across rounds and sessions. As long as the flow involves “the model starts a service and the next round needs it,” this plugin decouples the service lifecycle from the conversation lifecycle.

Note two points: The plugin runs with the current DSH process permissions, and services also run as the same user, outside the sandbox; it is recommended to check the source code and license (MIT) yourself before installation.

Conclusion

Recap: dsh-launch uses a detached broker process to solve the problem of background services being recycled with the session. Services continue running after the conversation ends, the session closes, or DSH restarts, while also providing three entry points: model tools, sidebar UI, and cross-plugin API. DSH’s philosophy is “everything is a plugin”; this approach of encapsulating infrastructure problems into plugins is worth referencing when building your own workflows.

  • GitHub: https://github.com/Khellendros97/dsh-launch
  • Community Directory: https://www.skillhub.cn/plugins/Khellendros97/dsh-launch (Community site, no official affiliation with DeepSeek / 幻方)