Service farm for DSH: register, start, stop and restart long-running project services, with agent tools (farm_status/start/stop/restart/logs/register), farm.yaml declarations and an overview drawer UI with live log follow, search and export.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:MarchLiu/dsh-farm
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
DSH service farm plugin: register, start, stop, restart and watch long-running project services — the agent can do it through tools, you can do it through the web UI.
Install
dsh plugin --profile <name> add /path/to/dsh-farm
Restart the DSH web surface afterwards.
What you get
UI: a 🚜 button at the sidebar foot with a running-services badge; clicking it opens the overview drawer — services grouped by workspace with status dots, start/stop/restart buttons, and a log view with live follow (SSE), substring search and download/export. With DSH-better-sidebar installed the same panel becomes a Farm tab in that sidebar instead — see Where the UI lives.
Delete: 🗑 on a row removes that one service.
☑ selectswitches the drawer into multi-select — tick rows (or select all), then delete (n) opens a confirmation dialog listing the targets; nothing is deleted until you confirm it.farm.yamlservices are greyed out in both paths: the file owns them, so you remove them by editing it.Agent tools:
farm_status/farm_start/farm_stop/farm_restart/farm_logs(service, tail, search)/farm_register(name, workspace, command, ...)/farm_unregister(service | services). Say "帮我把 dev server 注册到 farm 并启动" in a session and the agent does the rest.farm.yaml (optional, per workspace, commit-friendly):
services: dev-server: command: pnpm dev # cwd: sub/dir # optional, resolved against the workspace autoRestart: true env: PORT: 5173Declared services appear in the UI and
farm_statusautomatically (source: yaml); the file is always the source of truth.
Where the UI lives
dsh-farm renders its panel in whichever home is available, decided at runtime:
| DSH-better-sidebar | Where the panel appears |
|---|---|
| installed | a 🚜 Farm tab in better-sidebar (single-instance, with a running-count badge); dsh-farm's own footer button and drawer stand down |
| not installed | dsh-farm's own 🚜 footer button + right-hand drawer |
Nothing to configure, and better-sidebar is not a dependency — dsh-farm looks the service up by name at runtime and keeps working when it is absent. It also follows better-sidebar being enabled or disabled while DSH is running, in both directions.
Implementation note for anyone extending this:
betterSidebaris deliberately not in the client half'sinject. In DSH's cordis a declared-but-missing service parks the whole plugin, which would take the fallback UI down with it — the plugin would vanish entirely rather than fall back. The runtime's optional-lookup hook isctx.get('betterSidebar')(undefined when absent), andctx.on('internal/service', …)catches better-sidebar arriving or leaving later. That event can fire more than once for the same arrival, so registration is idempotent.
Behavior notes
- Services are spawned as children of the DSH process (
/bin/sh -c), so they are reclaimed when DSH exits. Dynamic registrations persist across restarts in$DSH_HOME/storages/dsh-farm/services.json(state does not). - Stop = SIGTERM, then SIGKILL after a 3s grace.
autoRestartretries an abnormal exit up to 5 times with exponential backoff (1s → 16s).- Logs: 5000-line in-memory ring per service plus an append-only file under
$DSH_HOME/storages/dsh-farm/logs/<id>.log. - Deleting a service stops it first, then drops its registry row, its live log
stream and its log file. Ids are derived from
workspace + name, so this keeps a later re-registration of the same name from inheriting stale logs. Project files are never touched.
HTTP API (localhost only, prefix /farm)
| Route | Meaning |
|---|---|
GET /farm/services?workspace= |
list (farm.yaml entries merged in) |
POST /farm/services |
register/update a dynamic service |
GET /farm/services/:id |
one service |
DELETE /farm/services/:id |
unregister one (stops it first; 400 for farm.yaml services) |
POST /farm/services/batch-delete |
unregister many — { ids: [] } → { ok, deleted, failed } |
POST /farm/services/:id/start|stop|restart |
lifecycle |
GET /farm/services/:id/logs?tail=&search=&export=1 |
logs, export=1 downloads |
GET /farm/services/:id/logs/stream |
SSE live follow |
Config (override in the profile patch)
- id: farm
config:
dataDir: /abs/path # default $DSH_HOME/storages/dsh-farm
ringLines: 5000
stopGraceMs: 3000
Links
More in this category
yjh051108/dsh-routing-suite★ 6997
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★ 3696
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.
first-fluke/oh-my-agent#dsh★ 1344
Runs project OMA checks before and after tool execution and when a turn tries to finish. Installs its OMA CLI dependency and initializes unconfigured projects on first use. Requires Node.js 22+; initial setup needs network access and project write access.
hust-open-atom-club/oh-dsh★ 322
Community distribution: TUI, desktop, and Web UI as one bundle with layered installation.
weijiafu14/pi2dsh★ 217
Pi Host ABI compatibility engine: after one install, unmodified Pi extensions from npm mount as native DSH plugins with `dsh plugin add <pi-package>`. Verified end to end on stock DSH with pi-mcp-adapter (full MCP manager: OAuth, resources, prompts, MCP Apps, elicitation, sampling), @tintinweb/pi-subagents, pi-code, pi-hermes-memory and pi-background-tasks; `pi2dsh inspect` reports a package's compatibility before installing.
Fishquito7/dsh-skill-mcp-panel★ 207
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.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.