Skip to content

dsh-machine-modes

Verified

dsh-machine-modes Β· v1.0.0 Β· MIT Β· Web UI

Session-level machine modes for DeepSeek Harness: run commands and file operations on the local host, a WSL distribution, a Docker container, or an SSH host, switchable mid-session, with tty and root escalation.

Install

dsh plugin add dsh-machine-modes

Confirm the layer applied with dsh --profile default --dump-config β€” see the install guide.

Source

Published to npm without a public repository. Inspect the package contents before installing.

Tags

Creators

Readme

dsh-machine-modes

Session-level machine modes for DeepSeek Harness.

Pick a machine β€” the local Windows host, a WSL distribution, a Docker container, or an SSH host β€” and that session's commands, background jobs and file operations run there. The model is told which machine it is on, how paths map, and how to switch, on every step.

● ε½“ε‰ζœΊε™¨ my-container                    /machine εˆ‡ζ’

Requirements

Harness DeepSeek Harness 0.2.0-rc.2 (@deepseek-ai/dsh-fs, @deepseek-ai/dsh-fs-sandbox)
Host OS Windows only β€” the transport is wsl.exe, so Linux/macOS hosts are not supported
Node >= 22.12
Optional Docker Desktop (for kind: docker), an SSH client (for kind: ssh)

Install

Ask your DSH agent to install it, or use the plugin manager directly with the npm spec:

plugin_manager  action: install_bundle  target: dsh-machine-modes

Then restart dsh and refresh the page. The plugin does not build anything: both halves are plain ES modules loaded at startup.

Read this before installing

This bundle replaces the filesystem provider: its patch disables the shipped fs-sandbox row and mounts dsh-machine-modes/fs instead. The replacement extends the stock class and delegates every path without a machine prefix to it, so ordinary local reads and writes (including the sandbox fence) behave exactly as before β€” but it is a core service swap, and you should know that before installing.

Two hard rules follow from that:

  1. Never hot-swap it. Applying the patch in a running process tears fs down under services that still hold it; that cascades into a dead back end. Install, then restart.
  2. Do not delete the package directory while it is installed β€” dsh will fail to start with no fs provider. Remove the bundle first, then delete.

Configure machines

Either edit the machine-modes row's config, or β€” simpler β€” create $DSH_HOME/machine-modes.json (%USERPROFILE%\.dsh\machine-modes.json on Windows). That file is re-read on every call, so adding a machine needs no restart:

{
  "default": "local",
  "machines": [
    { "id": "local", "label": "This Windows host", "kind": "local" },
    { "id": "wsl-ubuntu", "label": "WSL Ubuntu-24.04", "kind": "wsl", "distro": "Ubuntu-24.04" },
    { "id": "my-container", "label": "Docker container", "kind": "docker", "container": "my-container", "distro": "Ubuntu-24.04" },
    { "id": "vm-a", "label": "SSH host", "kind": "ssh", "host": "vm-a", "cwd": "/home/dev/project" }
  ]
}
Kind Fields Shell
local β€” Windows PowerShell 5.1
wsl distro bash, started in the session cwd mapped to /mnt/<drive>/...
docker container, optional distro (WSL distro that hosts the docker CLI) sh, preferring bash; the session cwd is not mounted, pass cwd or set it on the entry
ssh host (an ~/.ssh/config alias with key auth), optional cwd bash over ssh -o BatchMode=yes

What the model gets

Tool / command Purpose
machine / /machine Report the active machine and the roster, or switch ({"id":"…"}, /machine my-container)
exec Run a command on the active machine: command, cwd?, tty?, root?, background?, timeout_ms?
machine_auth Hold the sudo credential so exec {root:true} can escalate

Switches also show up in the conversation as a divider row that names both ends β€” local β†’ my-container (Docker container) β€” and the composer keeps a small card with the current machine. Both read the durable session history, not a guess.

Every step's prompt states the active machine and asks the model to batch cross-machine work: switch once per machine, run that machine's commands and file operations together, and switch again only when the next operations belong elsewhere. The switch is session-wide, so it governs everything after it.

File addressing

File tools (read/write/edit) keep their normal Windows paths for anything shareable, and take a machine URI for paths that only exist on the target:

read  wsl://Ubuntu-24.04/etc/os-release
write docker://my-container/tmp/notes.txt

glob and grep are local-only (they spawn ripgrep on the host); on a remote machine use exec with find / grep.

tty and root

exec {tty:true} allocates a pseudo-terminal inside the target (the command runs under script; its stdin is redirected to /dev/null so the pty does not echo the script back).

exec {root:true} escalates: docker exec -u 0 in a container, sudo -S in WSL/SSH with the credential from machine_auth. A passwordFile holds the account on its first line and the password on its second (a single line is treated as the password). Passwordless sudo is detected first. The local Windows host cannot be escalated from a tool.

Availability

WSL distributions and Docker containers come and go, so every entry point probes the target first: a WSL distribution must appear in wsl.exe -l -q, and a Docker container must report State.Running == true. Probes are cached for 15 seconds, warmed at startup, and invalidated as soon as a command fails.

When a machine is unavailable:

  • switching to it is refused, with the probe's own reason (WSL distribution "Ubuntu-99.04" is not installed (have: Ubuntu-24.04, docker-desktop));
  • exec refuses while the active machine is unavailable;
  • the roster marks it [unavailable: …];
  • the per-step prompt tells the model not to switch there.

SSH hosts are deliberately not probed β€” a probe would cost an SSH timeout every TTL β€” so they are always offered. The gate sits at the entry points: a container that stops while you are already inside it fails the next command for real, and the availability view can lag by up to the cache TTL.

Limitations

  • Windows host only (wsl.exe transport).
  • Replacing the filesystem provider is mandatory for the file layer; see the warning above.
  • Writes to remote paths are not fenced by the sandbox (local paths still are).
  • Container tty needs script inside the image (present in Debian/Ubuntu images, usually absent in Alpine).
  • The SSH kind has no remote filesystem layer: only exec works there.
  • The composer card derives from the loaded conversation window (400 nodes back); older switches fall back to a grey "observed/default" marker instead of claiming authority.

Uninstall

plugin_manager  action: remove_bundle  target: dsh-machine-modes

Restart afterwards; the shipped fs-sandbox row returns.

License

MIT