Model Router · DS Bot for DeepSeek Harness
English · 简体中文
dshfind
Want release notes only? Click Watch → Custom → Releases (you do not need Watching all activity).
One plugin that turns DeepSeek Harness into a Bot team: routing, budgets, official CLIs, remote
computers and a supervision workbench, mounted once inside the Harness you already run.
It is not a second application. There is no extra agent loop, no separate session store and no
other UI shell: every Bot keeps its own DSH Session, memory and interface, and the plugin adds
authority, accounting and control around them.
- Package:
@ljwei-stak/dsh-model-router
- Version: 0.27.1
- Harness: DeepSeek Harness Desktop 0.2.1-rc.4 / 0.2.1-rc.5
Install
Harness Desktop → Plugins → Add plugin, then enter the exact version:
@ljwei-stak/dsh-model-router@0.27.1
Upgrading keeps Bot configuration, credentials, session history, budgets and the operation ledger.
The plugin's own update check follows latest; prerelease builds ride the preview tag.
What you get
Bot team on one task system
Every Bot is a persistent identity with its own DSH Session, tools, machine and model binding. Work
is planned into packages, ordered by dependency, then executed with concurrency limits, review,
cancellation, reassignment and recovery. A task, its attempts, its budget reservation and its
receipt live in one transactional ledger, so a retried step cannot run twice or be billed twice.
Model and tool authority bound per Bot
A Bot's grant is compiled from committed Host state — never from model arguments or role text. The
same model can serve several Bots that keep separate identities. When a bound model is unavailable
the Bot pauses with a named reason instead of silently switching routes. Official CLI runs record
the requested model and the model the CLI actually reported; a reported reroute fails the
step instead of being accepted.
Official tools, including dsh-TUI
Thirteen registry entries with fixed install methods (npm, pnpm, vendor scripts, verified
archives): Kimi Code, Claude Code, Codex CLI, MiniMax Code, MiMo Code, Grok Build, Gemini CLI,
OpenCode, Step Code, Pi, Hermes Agent, ZCode CLI, and dsh-TUI — the DeepSeek terminal UI, which
DeepSeek providers name as their tool. Probe, version, login state and terminal launch come from
the same registry; nothing installs from a model-supplied URL or command.
Codex runs as a first-class sub-task (cli/codex) inside the task system. Claude's read-only step
keeps its normal reading tools, and the Host proves it changed nothing — a run that touches the
workspace fails with READ_ONLY_RUN_CHANGED_WORKSPACE instead of being reported as a successful
read.
Remote computers, and their desktop
Pair a machine running remote-computer-agent to get filesystem roots, shell_exec, artifacts and
a durable operation record per call. Model-facing remote tools and the human workbench share one
authorization path: a model never supplies an endpoint, executable path, task id or operation id.
电脑操作 (0.27.0) watches one desktop frame and acts on it. Frame and action are separate owner
calls; every action carries the id of the frame the person actually saw (single use, 15 s), clicks
map back to frame pixels, and each action runs as the chosen Bot under the same machine ceiling and
is recorded as an operation.
A workbench that answers the first question first
- 需要你处理 — derived from committed state: a paused budget, interrupted spend, a failed check,
a failed run, a tool that needs login, an unconfirmed remote effect. Healthy state renders
nothing.
- 演练 (dry run) — plan and price a run, list what each package would call, call nothing.
- 两本账 — API money (settled, reserved, limits, unknown prices) and subscription quota (calls,
reported tokens) as two books that are never added together.
- Terminals — PowerShell/system shell and the registry CLIs, with live output and sessions.
Routing that states its reasons
Economy / balanced / quality presets, exact model assignment per package, manual reassignment,
historical P90 estimates, dependency-aware search and quality evidence. A preview shows packages,
permissions, required confirmations and estimated cost before anything runs, and the Host rechecks
the plan at start.
First run
- Add a model route in Harness's Models page, then bind it to a Bot in Bot 绑定.
- Open 模型路由工作台 and read 需要你处理 — it stays empty until something actually needs you.
- Install the official tools you use; each card shows the exact command and target directory first.
- To use a remote machine, install
remote-computer-agent there, pair it with a ceiling of Bots,
roots and tools, then save its pairing token as a Host-only secret.
- Grant the Bot the remote tools it should have. A Bot that lacks a tool fails with a named reason
instead of falling back to something else.
Remote computer tutorial
This walks through giving a Bot a real computer: install the agent on that machine, pair it, grant
exactly what the Bot may do, then use it from chat or from the workbench.
1. How the three parts fit
your machine (DSH Host) the target machine (Agent) the Bot
┌──────────────────────┐ grant ┌─────────────────────────┐ tools ┌──────────────┐
│ machine catalog │ ────────► │ <agent-host>:9701 /mcp │ ◄─────── │ session-… │
│ ceiling, secretRef │ ticket │ roots, ceiling, ledger │ call │ grant │
└──────────────────────┘ └─────────────────────────┘ └──────────────┘
- The Agent runs on the target machine and owns the filesystem roots, the operation ledger and
every side effect.
- The Host (your Harness) stores the machine's pairing secret, issues a short-lived grant per
call, and keeps the Bot's authority.
- The Bot may only use tools that both its own grant and the machine ceiling allow. A model
never supplies an endpoint, path or task id.
2. Prepare the machine
| Requirement | Detail |
|---|
| OS | Windows 10/11 (x64) or Linux (x64/arm64). Desktop tools are Windows-only. |
| Node.js | 22.19 or newer (24.x recommended). Check with node -v. |
| Account | A normal account is enough; a dedicated low-privilege account is better. Do not run it as a Session 0 service if you want desktop control. |
| Network | Reachable from your Harness: a WireGuard/Tailscale private address, or HTTPS. A private IP is not trusted by itself — you attest the tunnel. |
| Disk | A workspace directory for each root you expose, e.g. D:\workspaces\project. |
3. Install the agent
Windows
powershell -File deploy/remote-agent/install-windows.ps1 `
-SourceRoot . -Prefix D:\dsh-agent -AuthorizedRoot D:\workspaces\project
Linux
sh deploy/remote-agent/install-linux.sh ./source ./dsh-agent /srv/workspaces/project
The installer copies the agent into a versioned directory, runs npm ci and the build, then
initializes config.json. It does not touch Node, the firewall, the VPN or any service.
No checkout on the target? Copy the agent folder (package.json, package-lock.json, build.mjs,
src/), run npm ci && npm run build, then
node dist/cli.mjs init <config.json> <authorized-root>.
4. Configure config.json
{
"dataDir": "D:\\dsh-agent\\data",
"roots": { "project": "D:\\workspaces\\project" },
"isolation": "application",
"network": {
"mode": "wireguard",
"host": "<agent-host>",
"port": 9701,
"protectedTunnel": true,
"allowedHosts": ["<agent-host>:9701"]
},
"executables": { "node": "D:\\Program Files\\nodejs\\node.exe" },
"windowsJobRunner": "D:\\dsh-agent\\native\\dsh-process-job.exe",
"desktop": {
"pipeName": "dsh-desktop-<host>",
"secretFile": "D:\\dsh-agent\\desktop.secret"
},
"browserOrigins": []
}
| Field | Meaning |
|---|
roots | Root ids the agent may touch. Tool paths are relative to one of them; traversal, ADS and symlink escapes are rejected. |
network.mode | loopback (default), wireguard, tailscale, cloudflare-tunnel, public-tls. |
network.host | Must be an address that exists on that machine (bind interface). Wildcards are rejected. |
network.protectedTunnel | Your explicit attestation that the address is reachable only over a private tunnel. Required for plain HTTP on a non-loopback address. |
network.allowedHosts | Exact host:port accepted in the Host header. |
windowsJobRunner | Job Object launcher. Without it Windows shell_exec fails explicitly instead of pretending to isolate. |
desktop | Pipe name and secret for the interactive desktop helper. Without it the five desktop_* tools are not exposed. |
5. Pair the Host
Write a ceiling — the most any client may ever ask for:
{
"botIds": ["<bot-session-id>"],
"roots": ["project"],
"tools": ["machine_ping", "fs_list", "fs_read", "fs_write", "shell_exec",
"operation_status", "operation_cancel", "artifact_stat", "artifact_read",
"desktop_screenshot", "desktop_click", "desktop_type", "desktop_key", "desktop_scroll"]
}
node dist/cli.mjs pair config.json host-office-pc ceiling.json
It prints three values once:
{ "clientId": "host-office-pc",
"token": "…43 characters…",
"machineId": "machine-…",
"secretRef": "remote-agent/machine-…/host-office-pc" }
token goes into a Host-only secret and nowhere else. Never paste it into a chat, a config
file, a model argument or a URL.
machineId identifies the machine in the Host catalog.
- Re-running
pair with an existing id fails by design; use rotate to reissue, revoke to
disable.
6. Keep the agent running
Windows — run it in the interactive session so the desktop helper can attach:
@echo off
cd /d D:\dsh-agent
"D:\Program Files\nodejs\node.exe" dist\cli.mjs serve D:\dsh-agent\config.json >> D:\dsh-agent\agent.log 2>&1
schtasks /create /f /tn dsh-remote-agent /tr D:\dsh-agent\start.cmd /sc onlogon /it
schtasks /run /tn dsh-remote-agent
netsh advfirewall firewall add rule name=dsh-remote-agent dir=in action=allow ^
protocol=TCP localport=9701 remoteip=10.0.0.0/24
Linux — use deploy/remote-agent/remote-agent.service.example as the template.
Check from the Host side: curl -i http://<agent-host>:9701/mcp must answer 401 (alive and
authenticated), never 200 and never a connection refusal.
7. Register the machine in the workbench
远程电脑 → 添加或重新配对电脑, in this order:
- 保存宿主专用凭据 — name it
REMOTE_AGENT_OFFICE_PC (uppercase letters, digits, underscores)
and paste the 43-character token. The result is ds-secret/REMOTE_AGENT_OFFICE_PC.
- Pairing form:
- 电脑名称: anything readable, e.g.
office-pc · Win11
- Agent machineId: the
machineId printed by pair
- Agent 地址:
http://<agent-host>:9701
- 凭据 secretRef:
ds-secret/REMOTE_AGENT_OFFICE_PC
- 已配对根目录 ID:
project
- 用于核验的 Bot: the Bot that will own this machine
- ☑ 受保护隧道 — required for plain HTTP on a private address
- Click 核验并配对, then 官方工具 · 体检 → 重新体检; the machine should be listed.
8. Grant the Bot its tools
A machine binding lists what the machine offers; the Bot's own grant lists what that Bot may use.
Both must contain a tool before a call succeeds.
| Tool | Does | Notes |
|---|
machine_ping | Agent health, OS, capabilities | Safe default |
fs_list / fs_read | List and read inside a root | Read-only |
fs_write | Atomic write with expectedHash | Mutating; null means create-only |
shell_exec | Fixed executable id or allowed interpreter, argv only | Needs windowsJobRunner on Windows |
cli_probe_v1 / cli_task_v1 | Versioned container/CLI backends | Only when a container profile exists |
operation_status / operation_cancel | Reconcile or stop an operation | A stop is not a confirmation |
artifact_stat / artifact_read | Read bounded output artifacts | Large output lands here |
worktree_create / worktree_diff / worktree_integrate | Isolated Git worktree and patch integration | Requires Git on the target |
browser_* | Playwright contexts with allowed origins | Browser presence is probed, not assumed |
desktop_screenshot / desktop_click / desktop_type / desktop_key / desktop_scroll | Interactive desktop | Needs the helper in the interactive session |
Start narrow: machine_ping + fs_list + fs_read. Add fs_write and shell_exec only when the
job needs them, and give them to one Bot rather than to Main.
9. Use it
From chat, ask the Bot directly: "read project/README.md", "run the tests", "open the internal wiki
and summarise it". The Bot picks a tool, the Host issues a grant for that one call, and the record
is kept.
From the workbench:
- 远程电脑 → 电脑操作: pick the machine and the Bot, click 截取当前画面, then click the
picture (that is a real click), or use the key row, the text box and the scroll buttons. Every
action is stamped with the frame id it came from; if the frame expired, take another one.
- 任务 / 运行记录: each call shows its operation id, status and artifact. Unknown outcomes are
reconciled there and never retried blindly.
10. Troubleshooting
| Symptom | Cause | Fix |
|---|
401 / AUTH_INVALID | Wrong, old or truncated token | Reissue with rotate, paste all 43 characters |
TLS_REQUIRED | Plain HTTP on a private address without attestation | Tick 受保护隧道 and re-pair |
BIND_INTERFACE_NOT_FOUND | network.host is not an address on that machine | Use the IP ipconfig / ip addr shows for the tunnel |
| Connection refused | Agent not running, or bound elsewhere | Check netstat; it must listen on the exact address |
MACHINE_BOT_DENIED | Bot grant or machine ceiling lacks the tool or root | Add it to both, re-save the binding |
MACHINE_GRANT_CHANGED | Ceiling changed mid-call | Re-run the action; the new revision applies |
INVALID_MACHINE_SECRET | Secret name or token shape is wrong | REMOTE_AGENT_* plus a 43-character token |
OPERATION_CONFLICT | Same operation id with a different request | Use a new operation; never reuse ids |
FRAME_UNAVAILABLE | Desktop helper not running, session locked, or UAC secure desktop | Unlock the machine, restart dsh-desktop-helper |
OUTCOME_UNKNOWN | Process died mid-operation | Reconcile with operation_status; do not replay |
11. Operate it
- Rotate:
node dist/cli.mjs rotate config.json <clientId>, then update the Host secret.
- Revoke:
node dist/cli.mjs revoke config.json <clientId>, then archive the machine.
- Upgrade: stop the agent, reconcile active operations, back up
data/ and config.json, install
the new version alongside, point the launcher at it, start again.
- Uninstall: stop tasks, remove the version directory, and delete config and data only after the
pairing is revoked.
12. What the agent does not promise
Roots are an application-level boundary, not an OS sandbox: a shell grant carries the account's own
permissions. For a real boundary use a dedicated OS account or a container profile. Desktop control
needs an unlocked interactive session, and one screenshot is not a video stream.
Security model in one screen
- Authority comes from committed Host state. Model arguments carry no tools, machines,
credentials, endpoints or task identity.
- Unknown is neither zero nor success. Unpriced calls stay unknown, unconfirmed remote effects
stay unknown, and only reconciliation resolves them.
- A stop is not a confirmation. A stop request is recorded; a remote operation counts as stopped
only with its own receipt.
- Every remote action is an operation. Duplicate ids return the original result; a changed
request with an old id is refused.
- Read-only is proven. A read-only CLI step that changes the workspace fails.
Compatibility and limits
Verified: the package installs and boots on 0.2.1-rc.4 and rc.5; the desktop app and packaged build
pass; the test suites pass offline; remote agent operations were exercised against a real machine
over WireGuard.
Not claimed: real-vendor acceptance for every CLI tool, a multi-monitor or DPI matrix for desktop
control, and installer/uninstaller acceptance on macOS. Where a capability is unverified the
interface says so instead of implying support.
Repository layout
.dsh-plugin/ host plugin: authority, tools, workbench RPC, client bundle
modules/bot-runtime/ the Bot runtime (vendored from ds-bot) and its policy scope
packages/ orchestration, capability broker, funding, tasks, remote execution
apps/integration-client/ product panels rendered inside the Harness sidebar
remote-computer-agent/ machine-side agent (MCP transport, operation ledger)
native/ Windows desktop and process-job helpers
together with each release's validation report.
License
MIT