Use DSH from iPhone/iPad: an explicit-opt-in LAN reverse proxy (Host/Origin rewrite through the loopback trust fence, WebSocket upgrades included), iOS PWA chrome (home-screen icon, standalone meta, viewport-fit), and touch/mobile CSS (safe areas, keyboard lifting, composer row fit).
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:cindyguyuehu123/dsh-mobile
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
Use DeepSeek Harness from your iPhone / iPad: LAN reverse proxy + iOS PWA (add-to-home-screen) + touch/mobile CSS for the web GUI.
DeepSeek Harness's web GUI binds to 127.0.0.1 by default (upstream deliberately rejects --host 0.0.0.0 for safety). This plugin adds a first-class mobile experience:
- 📱 LAN access — the plugin runs its own
0.0.0.0reverse proxy that forwards phone/iPad traffic to the loopback server, rewritingHost/Originso the/apitrust fence accepts it (HTTP and WebSocket upgrades included). The LAN URL and a terminal QR code are printed on startup. - 🍎 iOS PWA shell — injects
apple-mobile-web-app-capable,viewport-fit=cover,apple-touch-icon, programmatically generated PNG icons, and an enhancedmanifest.webmanifest. After "Add to Home Screen" in Safari it opens fullscreen like a native app with its own icon. - 👆 Touch adaptation — mobile CSS: inputs ≥16px to prevent iOS focus zoom,
touch-action: manipulationto kill double-tap delay, notch / home-indicator safe-area insets, raising the composer above the on-screen keyboard (visualViewport tracking), and larger tap targets for message actions. - 🔳 /mobile QR page — open
http://127.0.0.1:3080/mobileon the desktop to get a big QR code plus step-by-step instructions; the phone camera opens the LAN URL in one scan.
⚠️ Security warning (read first)
Enabling this plugin exposes the full Harness — including its code-execution tools — to every device on your LAN. That is the price of "usable from a phone". Please:
- only keep it enabled on a network you trust (e.g. your home Wi-Fi);
- on public/untrusted networks, comment out the
mobilerow incordis.patch.ymland restart; - optionally restrict access to specific phone IPs with the
allowconfig (see below).
🔧 Harness source patches (by need — no dsh-webchatlike dependency)
dsh-mobile itself does NOT depend on dsh-webchatlike — a stock harness without webchatlike works fine. Patches are applied as needed:
| Patch | Required? | Notes |
|---|---|---|
| Secure-context UUID | ✅ Required | Upstream bug: mintRpcId() uses crypto.randomUUID, a [SecureContext]-only API. http://127.0.0.1 is a trustworthy origin (local GUI fine), but a phone on a LAN IP is NOT a secure context → randomUUID is undefined → every RPC throws → the connection handshake fails → the page spins forever. Patches the stock files; unrelated to webchatlike. |
| webchatlike folding fallback | ⚪ Only with dsh-webchatlike | Fixes webchatlike's version-family folding on fresh browsers (no localStorage ledger): phones showed every regenerate/edit fork as an independent row and clicking the folded row did nothing. Not needed without webchatlike — stock harness never folds. |
Patch 1: Secure-context UUID (required)
| File | Change |
|---|---|
packages/host/apiproxy/src/fetch/client.ts |
mintRpcId() mints a v4 UUID from crypto.getRandomValues (core fix) |
packages/client/ui-conversation/src/client/service.ts |
Draft attachment ids use the same fallback |
packages/llm/llm/src/message.ts |
Message ids use the same fallback |
cd /path/to/deepseek-harness
pnpm run build:lib:client # the running GUI hot-swaps client bundles; no restart needed
All patches are backed up in
harness-patches/for re-application after upstream updates.
Patch 2: webchatlike folding fallback (optional, only with dsh-webchatlike)
packages/client/ui-workspace/src/client/tree.ts, WorkspaceBrowser.tsx, index.ts — also backed up in harness-patches/.
Install from GitHub
Repository: github.com/cindyguyuehu123/dsh-mobile (built lib/ ships with the repo — no build step needed)
Option 1 — official plugin command (clones and installs dependencies automatically):
dsh plugin --profile web add https://github.com/cindyguyuehu123/dsh-mobile.git
Option 2 — manual registration (same as dsh-webchatlike):
# 1. Clone and install dependencies
git clone https://github.com/cindyguyuehu123/dsh-mobile.git
cd dsh-mobile && pnpm install
# 2. Add to ~/.dsh/profiles/web/package.json dependencies
# "dsh-mobile": "link:/absolute/path/dsh-mobile"
cd ~/.dsh/profiles/web && pnpm install
# 3. Insert into ~/.dsh/profiles/web/cordis.patch.yml
# - insert:
# - id: mobile
# name: 'dsh-mobile'
Install (manual, detailed)
1. Build
cd /path/to/dsh-mobile
pnpm install
pnpm run build
Outputs: lib/index.js (host half) and lib/client.js (browser half, zero runtime imports).
2. Register in the profile
Edit ~/.dsh/profiles/web/package.json and add a link dependency:
"dependencies": {
"dsh-mobile": "link:/path/to/dsh-mobile"
}
Then:
cd ~/.dsh/profiles/web && pnpm install
Edit ~/.dsh/profiles/web/cordis.patch.yml, insert the loader row:
- insert:
- id: mobile
name: 'dsh-mobile'
3. Restart
cd /path/to/deepseek-harness
pnpm dsh web
The log prints:
dsh-mobile: 📱 phone / iPad access: http://192.168.x.x:3090
dsh-mobile: desktop QR page: http://127.0.0.1:3080/mobile
Usage
- Phone/iPad on the same Wi-Fi as the Mac;
- Scan the QR on the desktop
/mobilepage (or type the printed URL); - In Safari: Share → Add to Home Screen for a native-app-like icon.
Configuration
The plugin row accepts an optional config (all optional):
- insert:
- id: mobile
name: 'dsh-mobile'
config:
lanPort: 3090 # proxy port; walks +1 when busy (default 3090)
allow: [] # optional client-IP allowlist, e.g. ['192.168.1.20']; empty = allow all
How it works (no harness source changes needed for the plugin itself)
- The upstream WebServer's
/apiroutes and WebSocket upgrades all passisTrustedApiRequest: loopbackHostpasses,Origin(when present) must be same-origin. The proxy rewritesHostto127.0.0.1:<loopback port>and same-originOriginaccordingly, so phone traffic looks exactly like local traffic to the core server — no harness source modification, and the blocked--host 0.0.0.0is never touched. - PWA parts use the public
webServer.tapIndex()and route-registration extension points. - The browser half rides the standard
dsh.clientchannel (/plugins/dsh-mobile/client.js), same loading path as the shipped ui-* plugins.
Development
pnpm run build # build lib/ via tsdown
pnpm run typecheck # tsc --noEmit
Client-side changes hot-swap into a running GUI (bundle polling); host-side changes need a dsh web restart.
Known limitations
- LAN-only (or your own tunnel): the phone cannot reach the Mac over cellular.
- macOS may ask once to allow Node.js to accept incoming connections — allow it.
- Real-device keyboard/safe-area behavior is covered for mainstream iOS, but minor per-version differences may remain.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| "Cannot connect" / endless spinner | Phone not on the same network, router AP isolation, or iOS Local Network permission off | Same Wi-Fi; disable AP isolation on the router; Settings → Privacy & Security → Local Network → enable browser |
| Blank spinning page | Old cached bundle (pre-fix) | Refresh; private window; clear Safari cache |
| Works on Mac only | macOS firewall | System Settings → Network → Firewall → allow Node.js |
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-remote-web-ui★ 8178
Remote control of a dsh web workspace from phone or PC: QR-code pairing through a token-gated channel, SSE real-time sync, and separate mobile and full desktop GUI modes.
zhu1090093659/dsh-web#packages/dsh-ssh★ 8178
SSH ops panel for DSH: web terminal, SFTP transfer with progress, local port forwarding, and one-command cluster execution across hosts; agents share the same host config.
saya-ch/dsh-mobile★ 341
Access DeepSeek Harness from the Android app or a mobile browser with secure LAN and remote connections, persistent device pairing, and a customizable mobile interface.
ZSeven-W/dsh-ios★ 309
A live iOS Simulator or USB-connected iPhone inside the conversation: 22 agent tools for booting, building, driving the UI by accessibility identity or OCR text, list-row actions and SwiftUI preview hot reload, plus a streaming sidebar panel you can tap and drag on.
liguobao/ds-harness-remote★ 242
Multi-device remote access for DeepSeek Harness: continue an active session from your phone, tablet, browser, or another computer over an end-to-end encrypted channel (Noise IK + adaptive relay/WebRTC transport), with device authorization, ApiProxy-only remote capabilities, and read-only file preview via dsh-file-viewer — no shell, remote desktop, or write access.
wenbin-wb/dsh-bridge★ 179
Remote and mobile access for DeepSeek Harness: provides LAN QR code connection, Cloudflare/custom tunnels, WeChat, QQ, Feishu, Telegram bot integration, and security authentication.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.