deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
A DeepSeek Harness plugin that adds the ssh_exec model tool — run commands on a remote Linux server over the system ssh client — plus persisted SSH connections: save connections once, bind them to a workspace, and let ssh_exec use them by default.
BatchMode=yes) — no password/passphrase prompts, so a missing or unauthorized key fails fast instead of hanging.bash -s.danger-full-access runs it unconfined.~/.ssh/config — hosts defined there need no manual ssh_connections save; pass the alias as ssh_exec host and ssh resolves it, and ssh_connections list shows them read-only.ssh-connections settings namespace and the ssh_connections tool; the browser half registers the "SSH Connections" card in Settings → Plugins.tools/shell are optional — profiles without settings or workspaceRegistry degrade gracefully (see below).dsh plugin --profile <name> add dsh-ssh-plugin # from npm
dsh plugin --profile <name> add github:you/dsh-ssh-plugin # from git
dsh plugin --profile <name> add ./dsh-ssh-plugin # from a local checkout
A local checkout must be built first: pnpm install && pnpm bundle (git installs build automatically through prepare).
Then boot with dsh --profile <name>.
The plugin declares the harness packages as peer dependencies; @deepseek-ai/dsh-base (the first bundle of every profile) provides them.
The model gains an ssh_exec tool. Ask in natural language (e.g. "ssh to root@10.0.0.5 and show disk usage"), or pass explicit arguments:
| Arg | Required | Notes |
|---|---|---|
host |
yes* | Remote host as [user@]host, e.g. root@10.0.0.5, or any alias defined in ~/.ssh/config. |
command |
yes | Bash command(s) run on the remote host via bash -s. |
port |
no | SSH port. Default 22. |
key_path |
no | Absolute path to the private key. Omit for ~/.ssh defaults and ssh-agent. |
timeout_ms |
no | Foreground timeout in ms. Default 30000. |
connection |
no | Label of a saved connection; fills in host/port/user/keyPath. |
* host is required in the schema, but at execution the effective host resolves as explicit host → explicit connection → workspace default. Explicit port/key_path always win over the resolved connection's values. A host that is a ~/.ssh/config alias is handed to ssh unchanged — ssh applies the config's HostName/User/Port/IdentityFile itself, so no ssh_connections save is needed for config hosts.
The model also gains an ssh_connections tool for durable connection management (persisted through the harness settings store, so it survives restarts):
save — persist a connection (label, host, optional port/user/keyPath). Labels are unique.list — show saved connections plus hosts discovered from the local ~/.ssh/config (read-only; pass the alias as ssh_exec host, no save needed).delete — remove one by label (also unbinds workspaces that pointed at it).use — bind the current workspace to a connection label so ssh_exec may omit host; omit label to clear the workspace default.On every call the plugin reads the local OpenSSH client config (~/.ssh/config, or sshConfigPath when configured) and parses it:
Host aliases become visible to the model in ssh_connections list and are suggested in ssh_exec error messages.Host * blocks provide defaults, later matching blocks cannot override them. HostName/User/Port/IdentityFile are resolved; Match blocks and Include directives are not expanded — hosts must live in the file itself.~/.ssh/config.With a web profile, Settings → Plugins shows an "SSH Connections" card styled like the built-in plugin cards (Bash/Terminal, Agent loop, Web search): a collapsible card with an unsaved badge and discard/save actions. Edit the same connections list (add/remove rows, save). The card only writes the connections field; workspace bindings are managed by ssh_connections use.
The ssh-connections settings namespace (schemastery schema, validated for duplicate labels):
{
connections: [{
label: string // unique, non-empty
host: string // [user@]host, non-empty
port?: number // 1..65535, default 22
user?: string // optional; prepended to host when host has no user part
keyPath?: string // absolute private-key path; omit for ~/.ssh + ssh-agent
}],
workspaceDefaults: { [workspaceId: string]: string } // workspaceId → label
}
Only key paths are stored — key content never leaves disk (role('secret') is reserved for a future keyContent field).
Set row-level defaults in a later patch layer (profile cordis.patch.yml or --patch):
- id: tool-ssh
name: dsh-ssh-plugin
config:
timeoutMs: 30000
connectTimeout: 15
sshConfigPath: C:\Users\me\.ssh\config # optional; defaults to ~/.ssh/config
| Composition | Behavior |
|---|---|
No ctx.settings (e.g. TUI) |
No namespace, no ssh_connections tool; ssh_exec works with explicit args only. |
No ctx.workspaceRegistry |
use and the workspace-default resolution report "workspace registry unavailable"; everything else works. |
No ~/.ssh/config (or unreadable) |
ssh_connections list shows saved connections only; ssh_exec suggestions omit config aliases. |
| Namespace not exposed to the browser | The card renders an "unavailable" placeholder. |
~/.ssh/authorized_keys).danger-full-access; the restricted token otherwise refuses to start ssh.exe.pnpm install
pnpm bundle # tsdown → lib/index.js (host) + lib/client.js (browser bundle)
pnpm types # tsc --emitDeclarationOnly → lib/types/**/*.d.ts
pnpm test # vitest (model + wiring) CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。