DeepSeek Harness Plugin

JochenYang/dsh-remote#dsh-remote

Stars ★ 0 Category Remote & Mobile Added 2026-08-29

Use DSH from your phone anywhere: a self-hosted relay plus a desktop host plugin form a token-authenticated tunnel (order-preserving HTTP reverse proxy + WebSocket bridging) with QR pairing, an admin console for device/token management, and an injected mobile adaptation layer (full-width chat, full-screen settings sheet, sidebar drawer).

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:JochenYang/dsh-remote#path:/dsh-remote

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

dsh-remote — Mobile Remote (Desktop Host Side)

简体中文 | English

Operate DeepSeek Harness from a phone browser as if it were the desktop: a self-hosted relay-server shuttles traffic (HTTP reverse proxy + WebSocket frame bridging) with zero changes to the dsh core or frontend, and injects a mobile adaptation layer automatically.

Architecture

Phone browser ──HTTPS──> relay-server ──WS frames──> dsh-remote (plugin) ──HTTP/WS──> local dsh web server
    │                     │  └────────── downstream event streams ──────────┘     (127.0.0.1:<port>)
    └── pairing: 6-digit code + challenge-response ──┘

Features

  • Full tunnel: every phone request under /d/<deviceId>/* is reverse-proxied to the local dsh web server; SSE/blob streams are re-chunked frame-by-frame in order; /events/mux and /events/host are bridged bidirectionally.
  • Trust-header stripping: origin / sec-fetch-* / referer are removed before forwarding so tunneled traffic passes dsh's /api Host fence (otherwise every API call gets a 403).
  • Settings unlock: the dsh web client gates its settings mirror on the page hostname, which never qualifies behind a relay. The plugin rewrites the single ui-settings client bundle in transit, restoring the model catalog, plugin config sections and every other settings surface (describe answers are redacted upstream; secret material never rides the wire).
  • Mobile adaptation layer: a responsive stylesheet injected into tunnel HTML (≤720px full-width chat / full-screen settings sheet / clamped dropdowns; ≤1024px overlay sidebar drawer). Desktop and GUI traffic never crosses the plugin, so it stays pixel-identical.
  • Pairing UX: 6-digit pairing code + QR code; code refresh waits for the relay's reply before answering; copy feedback; expired codes flagged in red.
  • Session control: one click revokes every paired phone session.

Requirements

  • DSH (DeepSeek Harness) desktop with the web profile (the plugin mounts its webServer).
  • Node.js ≥ 22 (the agent uses the native global WebSocket).
  • A deployed self-hosted relay (see relay-server).

Install

Download dsh-remote-<ver>.tgz from Releases, then:

# Install into the dsh web profile, then restart DSH
dsh plugin --profile web add ./dsh-remote-<ver>.tgz

Or build from source (inside this directory):

pnpm install
pnpm build            # host-side esbuild bundle
pnpm build:client     # settings-page client bundle
pnpm pack             # produces dsh-remote-<ver>.tgz
dsh plugin --profile web add ./dsh-remote-<ver>.tgz

Configuration

Open Settings → Phone Connection:

Option Description
Relay URL the relay's HTTPS address (e.g. https://relay.example.com)
Relay token the HOST_TOKEN configured at relay deploy time
Auto-connect on startup register with the relay as soon as DSH starts

Settings persist at <dshHome>/storages/dsh-remote/config.json. Once online the panel shows a 6-digit pairing code (10-minute TTL) and a QR code; pair by scanning, or by entering the code at <relay>/pair on the phone.

How It Works

  • Uplink: phone request → relay → this plugin → local dsh web server, with the response streamed back frame-by-frame (frame order = stream order).
  • Downstream: the two dsh event streams (/events/mux, /events/host) are WebSockets; the relay forwards ws-open/ws-frame/ws-close frames and the plugin mirrors them onto an equivalent local WebSocket.
  • Keepalive: 30s ping/pong, 90s silence kill; reconnects back off exponentially (1s→60s).

Wire formats, handshake flow and security parameters: docs/PROTOCOL.md (carry the file along when publishing standalone).

Development

pnpm build            # host-side build (esbuild, no type checking)
pnpm typecheck        # host-side type gate
pnpm typecheck:client # settings-page client type gate
pnpm pack             # pack the tgz

The tsconfig @deepseek-ai/* type mappings point at a local deepseek-harness checkout (../../deepseek-harness). CI only runs build + node --check.

Security

  • HOST_TOKEN is the relay's single trust boundary; the plugin adds no second auth layer and keeps the token local.
  • Pairing codes live 10 minutes with one-shot 60s challenges; codes and tokens are never logged.
  • To the local dsh server, tunneled traffic reads as the loopback client it physically is; the trust boundary lives in the relay's phone-session auth.

License

MIT © 2026 JochenYang

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.