deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
Manage remote DeepSeek Harness instances over SSH, with the local machine as a thin client — the same model as Codex Remote.
A remote harness runs on an SSH host (agents, bash/fs tools, sessions, and the workspace all live there). The local machine only:
ssh -L), andhttp://127.0.0.1:<local-port>.Nothing heavy runs locally — the browser is the client, exactly like Codex
Remote. This works out of the box because dsh's web surface is already a
browser → harness client-server architecture (/api over HTTP/WS), and dsh
deliberately refuses --host 0.0.0.0, so the SSH tunnel is the sanctioned way
to reach a harness from another machine.
The plugin ships two halves:
| Piece | What it does |
|---|---|
dsh-ssh CLI (bin/dsh-ssh.js) |
Standalone command: add/list/status/connect/disconnect/open/setup/start/stop/logs |
dsh profile bundle (lib/index.js + lib/client.js) |
Installed into the local web profile; adds an SSH Remotes panel to Settings and an /ssh-remotes HTTP route |
Both halves share the same logic (lib/config.js, lib/tunnel.js,
lib/remote.js, lib/browser.js).
Prerequisites: dsh ≥ 0.1.0-rc.6 (the web profile), ssh on PATH, and pnpm
(npm i -g pnpm if dsh plugin reports pnpm missing).
Install the plugin into your local web profile (takes effect on the next
dsh web start):
dsh plugin --profile web add /path/to/dsh-plugin-ssh
For the standalone CLI without a profile, run bin/dsh-ssh.js directly
(node /path/to/dsh-plugin-ssh/bin/dsh-ssh.js ...) or symlink it:
ln -s /path/to/dsh-plugin-ssh/bin/dsh-ssh.js ~/.local/bin/dsh-ssh
# 1. Configure a remote (hostname or ~/.ssh/config alias)
dsh-ssh add prod --host my-server --user deploy --workspace /srv/app
# 2. Provision the remote: check node, install dsh, create the workspace,
# copy local LLM credentials (settings.yaml), and launch the harness
dsh-ssh setup prod --copy-settings
# 3. Connect: tunnel to the remote harness and open it in the browser
dsh-ssh connect prod # adds --no-open to skip the browser
dsh-ssh open prod # re-open the browser at the existing tunnel
# 4. Inspect / manage
dsh-ssh status prod # tunnel + remote process + harness health
dsh-ssh logs prod # tail the remote harness log
dsh-ssh stop prod # stop the remote harness process
dsh-ssh disconnect prod # tear down the tunnel
Then, in the local web GUI: Settings → SSH Remotes lists every configured remote with live status and Connect / Open / Disconnect / Start / Stop / Logs buttons.
On the new-session screen, an SSH 远端 chip sits beside the "选择工作区" chip: click it to list configured remotes and pick one to connect — the current page then navigates to that remote's harness GUI, so your workspace becomes the remote's (the local page is replaced). The same in-place navigation applies to Connect / Open in the Settings → SSH Remotes panel.
dsh-ssh add <name> --host <host> [options] add/update a remote
dsh-ssh rm <name> remove a remote
dsh-ssh list list remotes with a short status
dsh-ssh status [name] detailed status (all by default)
dsh-ssh connect <name> [--no-open] tunnel + open the remote GUI
dsh-ssh disconnect <name> | --all stop the tunnel
dsh-ssh open <name> open the browser at an existing tunnel
dsh-ssh setup <name> [--copy-settings] provision the remote and launch
dsh-ssh start <name> (re)start the remote harness process
dsh-ssh stop <name> stop the remote harness process
dsh-ssh logs <name> [--lines N] tail the remote harness log
add options:
| Option | Meaning | Default |
|---|---|---|
--host <host> |
SSH host or ~/.ssh/config alias (required) |
— |
--user <user> |
SSH username | ssh config |
--port <port> |
SSH port | 22 |
--identity <path> |
private key path (~ expanded) |
ssh default |
--jump <host> |
jump host for -J |
— |
--workspace <path> |
remote working directory for the harness | — |
--remote-port <p> |
port the remote harness listens on | 3080 |
--local-port <p> |
local tunnel port; 0 = auto-pick |
0 |
--launch <cmd> |
override launch command; {dsh}/{port} placeholders |
{dsh} web --port {port} --host 127.0.0.1 |
--ssh-args <a> |
extra ssh option (repeatable) | — |
Global flags: --json (list/status), --home <dir> (override DSH_HOME).
Remotes live in $DSH_HOME/remotes.json (default ~/.dsh/remotes.json):
{
"remotes": {
"prod": {
"host": "my-server",
"user": "deploy",
"port": 22,
"identity": "~/.ssh/id_ed25519",
"jump": null,
"workspace": "/srv/app",
"remotePort": 3080,
"localPort": 0,
"launch": null,
"sshArgs": []
}
}
}
Runtime tunnel state is kept per remote in $DSH_HOME/remotes-state/<name>.json
so a later disconnect/status can find the spawned ssh process.
On the remote, the plugin records its own state at
~/.dsh/remotes/<name>.json (pid, log path, port) and writes the harness log
to <workspace>/.dsh-ssh.log.
dsh-ssh setup)~/.nvm exists, it installs Node via nvm (--node-major, default 22)
— user-local, no sudo.dsh; if absent, runs npm install -g @deepseek-ai/dsh under the
active node.~/.dsh/settings.yaml (LLM provider config) to
the remote — or keep the remote's credentials managed independently.dsh web --port <remote-port> --host 127.0.0.1 inside the remote
workspace with nohup, records the pid, and detaches. When dsh runs under
nvm, the launch activates that runtime so the shebang's node resolves
correctly.The remote harness binds only to the remote's own 127.0.0.1, so it is never
exposed to the network; the only way in is your SSH tunnel.
LLM credentials on the remote: the harness reads
$DSH_HOME/settings.yamland the.envfile in its working directory (dsh loads.envfrom cwd). Set the API key on the remote (e.g. writeARK_PLAN_API_KEY=…into<workspace>/.env, or put the value in~/.dsh/settings.yamlon the remote) so agents can run there.
dsh-ssh connect picks a free local port, spawns
ssh -N -L <local-port>:127.0.0.1:<remote-port> [-p P] [-i key] [-J jump] user@host
as a detached background process, then polls http://127.0.0.1:<local-port>/
until the dsh boot marker (window.__DSH_BOOT__) appears. Because the browser
talks same-origin /api, a page served over the tunnel is automatically a full
client of the remote harness — including all tools, sessions, and jobs, which
execute on the remote.
The bundle adds an sshRemotes host service and, when the web profile is
composed, an /ssh-remotes HTTP route (loopback-origin only). The browser half
registers a Settings → SSH Remotes section that lists remotes and drives
the same operations the CLI does.
BatchMode=yes — set up key-based auth or an ssh agent;
interactive password prompts are intentionally not supported.StrictHostKeyChecking=accept-new keeps first connects painless without
weakening existing known_hosts.127.0.0.1 on the remote and is reached only
through your tunnel./ssh-remotes route rejects non-loopback Origin headers. It is
not a security boundary — the whole local harness already trusts
127.0.0.1 — but it prevents cross-site calls from a remote page.MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。