Introduction

There are two common approaches to letting models operate remote servers: deploying an agent on the target machine, or giving the agent full shell permissions. The former requires maintaining an extra resident process, while the latter implies that a high-risk command might run on a production machine without any confirmation.

dsh-remote-server offers another combination: it installs nothing on the server, executes commands via your existing SSH client, but every command must pass through a fixed-order approval pipeline—anything not explicitly allowed falls to humans, ending with a refusal if humans are unreachable.

What is this

dsh-remote-server is a plugin for DeepSeek Harness (hereinafter DSH) by MRZHUH, licensed under MIT, current version 0.1.1. The philosophy of DSH is “everything is a plugin”; this plugin adds an @ mention capability to the session: input @ to list registered servers, select one to reference along with the message, and the model explicitly writes the target server on every command.

The official one-sentence positioning: In DSH sessions, mention servers via @, execute commands via SSH on them, and place all commands behind a two-tier approval threshold in a fail-closed manner.

Core Features

Install Nothing on the Server

This is the core design of the plugin and deserves its own section:

  • No agent, no daemon, and no inbound ports on the target machine. The plugin drives your own SSH client, so your existing ~/.ssh/config continues to take effect—jump hosts, agent forwarding, and known_hosts require no changes.
  • Authentication is key-only. The identityFile is simply the path handed to the SSH client; the plugin never reads, copies, or stores key material. The password field is rejected rather than stored.
  • The machine running dsh must have an OpenSSH client. If ssh is missing, the plugin will fail during loading and provide the installation command for the corresponding platform, rather than leaving the system in a broken state.

Register Servers

There are two paths:

  1. Add in Settings -> Servers -> Add a server;
  2. Or write to the remote-servers settings namespace (YAML).
remote-servers:
  servers:
    - alias: web-01
      host: 10.0.0.11
      user: ops
      tags: [prod, web]
      description: edge tier - start here
    - alias: db-01
      host: db-01.internal.example
      port: 2222
      identityFile: ~/.ssh/id_ed25519_db

alias is the name you type after @ and cannot contain whitespace; configuration items include alias, host, user, tags, description, as well as optional port and identityFile.

You can also import existing configurations: the import function reads ~/.ssh/config (or a path you specify), lists hosts for you to select and register; during a re-scan, it will prompt which hosts are already registered rather than listing disabled duplicates.

If a server rejects your key, the server page will provide a ssh-copy-id command with your username, host, and port pre-filled.

Two Tools and Server Info Page

The plugin exposes two tools to the model:

Tool Function
remote_exec Run a command on a single registered server, returning stdout, stderr, and exit code
remote_server_info Read collected server information, or re-probe the machine

Each server has a dedicated info page: reachability, the description you wrote, and the machine’s own data—hostname, OS, CPU, memory, disk, uptime—all collected in a single SSH round trip. Unchecked servers will truthfully display “unchecked” rather than placeholder numbers. The page title also displays the version of the installed plugin package.

Approval Pipeline

Every command must pass through a fixed-order pipeline, and the order itself is part of the design:

  1. Unregistered alias: Directly reject, do not initiate a connection.
  2. Full access: Under the DSH danger-full-access and never permission combination, commands for registered servers no longer prompt twice.
  3. High-risk rule set: A deterministic match triggers a forced human decision; the model classifier cannot overturn this.
  4. alwaysAsk: Once set, all commands from this point onward are handed to humans.
  5. Read-only allowlist: Normal calls matching configured prefixes execute immediately.
  6. Model classifier: Answer auto or human for the remaining commands.
  7. Human approval: Ask via the DSH approval channel.

Nine high-risk categories force a human decision: recursive deletion, disk and filesystem writes, shutdown and reboot, service stop and restart, user and permission changes, package installation and uninstallation, writing to system paths, privilege escalation, and reading credentials or key paths.

The meaning of fail closed is: any command that cannot be given explicit permission falls to humans; classifier timeout, errors, or vague answers do not count as a pass—the rejection branch is the default path in the code, not the error handling branch.

Enabling Model Auto-Approval

Auto-approval is off by default until you specify the model in the configuration— the plugin cannot predict which provider you have deployed in your combination. In the profile’s cordis.patch.yml:

- id: remote-server
  config:
    classifier:
      provider: deepseek
      model: deepseek-chat

The provider and model must be set together or not at all; setting only one will fail on load. This step does not involve an API key: the plugin calls via ctx.llm, and credentials are parsed by the harness; the plugin itself touches no keys.

Installation and Enablement

Install from npm:

dsh plugin --profile web add dsh-remote-server

Then start dsh web as usual (equivalent to dsh --profile web). --profile specifies which combination to load: a profile is a set of loadable plugins under $DSH_HOME/profiles/, allowing daily environments and clean environments to coexist; web is the set the quickstart defaults to. The published tarball is built, requiring no manual edits or extra licenses.

If the dsh command is not in your PATH, you can run it using npx or install it globally:

npx @deepseek-ai/dsh web
# or
npm install -g @deepseek-ai/dsh

Note to keep the full package name scope: writing just npx dsh will pull an unrelated package and report could not determine executable to run.

Install from source:

dsh plugin --profile web add github:MRZHUH/dsh-remote-server

A git install pulls the source code rather than the build artifact; pnpm needs to run the package’s prepare script to compile it. The first add will fail and print the configuration key to add to pnpm-workspace.yaml (in older pnpm versions this key is called allowBuilds):

onlyBuiltDependencies:
  - dsh-remote-server

Allowing this line means allowing the package to execute code on your machine during installation. It is recommended to also use github:MRZHUH/dsh-remote-server#<sha> to pin the commit, avoiding subsequent silent changes to what runs. Installing from npm does not require this permission because the released tarball is already built.

Missing peer warnings (@deepseek-ai/dsh-*, @deepseek-ai/cordis, react) that appear during installation are expected behavior: these peers are provided by the dsh installation itself at runtime and are not in the profile’s node_modules, so the plugin works normally.

Uninstalling only requires one command, and registered servers are preserved:

dsh plugin --profile web remove dsh-remote-server

Configuration Items

Two verified configuration items: connectTimeoutMs defaults to 10000, constraining the connection establishment process; execTimeoutMs defaults to 120000. The configuration table in the README is truncated after this; for other configuration items, refer to the original repository text.

Typical Usage

After installing the plugin and registering a server, the flow is as follows:

  1. Input @ in the session and select a server from the list;
  2. Speak your requirements in natural language, referencing them passed along with the message; the model explicitly writes the target server on every command;
  3. Read-only commands execute immediately; any commands that change state will stop and ask you first.

If you want the classifier to automatically approve some commands, configure the provider and model in cordis.patch.yml as described above; not configuring it keeps the default behavior of requiring human confirmation for all commands.

Applicable Scenarios and Notes

Suitable scenarios:

  • Developers and operations personnel who already have an SSH system and ~/.ssh/config but want the model to run remote commands without introducing an agent on the target machine;
  • Environments that require the default strategy of “read commands execute immediately, state-changing commands must be confirmed by a human”.

A few notes:

  1. The plugin runs with the permissions of the current dsh process. Check the source code and license before installing (this project is MIT). Installing from source is especially important to understand: allowing the prepare script is equivalent to allowing the package to execute code on your machine during installation; it is recommended to pin the commit.
  2. The machine running dsh must have an OpenSSH client; if it is missing, the plugin will fail directly upon loading.
  3. Regarding the release process: GitHub Release tags matching v<package.json version> trigger .github/workflows/publish.yml, publishing via npm trusted publishing with provenance, and do not use the NPM_TOKEN secret.

Conclusion

The value of dsh-remote-server lies in changing the default path of “letting the model touch the server” from execute to reject: no agent installation, no key storage, read commands go through the allowlist and execute immediately, nine high-risk categories force human decision, and the classifier defers to humans when uncertain. If the model and SSH are already inseparable in your workflow, try the steps above.

  • Directory page: https://www.skillhub.cn/plugins/MRZHUH/dsh-remote-server
  • GitHub: https://github.com/MRZHUH/dsh-remote-server

Note: skillhub.cn is an independent community plugin directory and has no official affiliation with DeepSeek / Hypersphere.