Drive your dsh agent from WeChat over the iLink gateway: two-way encrypted media transfer (auto-decrypt inbox + /send), proactive weixin_send tool, completion notifications, multi-session switching, and a health panel with file logging.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-mobile-remote
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:good-boy4069/dsh-mobile-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
Your phone's WeChat becomes the remote control for your DeepSeek Harness agent.
Scan a QR code to bind a WeChat bot, then drive your dsh agent from WeChat over any network (4G / any WiFi): send commands, assign tasks, receive results, browse directories with /ls — plus two-way file transfer, proactive notifications, and multi-session switching.
- Full-permission mode: the agent can use every tool without confirmation (a
strictescape hatch is reserved viapermissionMode) - Voice messages: never stored or transcribed; replies「无法识别语音消息」(voice message not recognized)
- Messages transit Tencent iLink servers (WeChat has no third-party API) — not end-to-end encrypted; see "Risks & Boundaries"
Why this plugin
Compared with other dsh WeChat bridges (dsh-weixin, dsh-chatnode-wechat, dsh-im-bridge, …):
- Protocol fidelity: every wire detail was verified line-by-line against Tencent's official openclaw-weixin SDK v2.4.6 (notes and reference sources in
docs/) — outboundaes_keyencoding, the two separate media-type numbering schemes, and the CDN upload/download flows all match the official SDK. Both inbound AES key encodings (base64 of raw bytes / base64 of hex) are supported, with explicit errors on bad keys (no silent truncation) - Two-way file transfer: inbound images/files/videos are downloaded, decrypted and saved automatically (stable naming to prevent crash-replay duplicates + plaintext MD5 verification + 100 MB cap); outbound via the
/sendcommand or a[[send-file:path]]line in the model's reply — both share a single allowlist path check (symlink escapes, out-of-root paths and directories are rejected) - Proactive notifications: a
weixin_sendmodel tool (text + file) plus completion notifications for unbound sessions (rule-based dedup against double-send). Expired session tokens (-14) return an exact message, the health panel degrades and prompts a re-scan, and re-scanning while running hot-rotates credentials without a restart - Multi-session remote control:
/sessionslisting +/switchwith number/title dual semantics; when a session is taken over by another chat, the previous chat is notified — no cross-window output mixing - Reliability engineering (rare among peers): an exactly-once processing pipeline (queue + cursor atomically persisted), an at-least-once delivery outbox with crash recovery, a global processing limiter (8) + download semaphore (3) + backpressure throttling, drain re-entrancy mutexes and cursor identity checks, redundant credential persistence; 182 automated tests green, strict typecheck, and a zero-value-import gate for host packages
- Observability: a
/healthendpoint (allowlisted fields, no internal identifiers), a three-state status bar on the login page (running / missing credential / stopped + reason), and agateway.logfile log (1 MB rotation, 0600) - Clear security boundaries: the allowlist is the only usage boundary, the login page is loopback-only, error texts never leak keys or paths, and
weixin_sendfile sending is constrained by the same path allowlist as/send
Install
# 1. Install the plugin into the web profile
npx @deepseek-ai/dsh plugin --profile web add dsh-mobile-remote
# 2. Start (or restart) dsh web
dsh web
QR login
- With
dsh webrunning, openhttp://127.0.0.1:3080/mobile-remote-weixin/loginin a browser on this machine - Scan the QR code with WeChat and confirm (if WeChat shows a numeric code, enter it on the page)
- Once confirmed, message the bot from WeChat
The login page shows a gateway status bar (green = running / yellow = missing credential / red = stopped + reason); GET /mobile-remote-weixin/health returns a health snapshot (loopback-only, no internal identifiers).
Commands
| Command | Effect |
|---|---|
/status |
Session state + session id + workspace |
/new |
Unbind current session; next message starts a new one |
/stop |
Stop the running task |
/reply <text> |
Follow up on the current task |
/sessions |
Last 10 sessions (current binding marked ⭐) |
/switch <number-or-title> |
Switch session: pure digits resolve by /sessions number first, fall back to title match |
/切换聊天窗口:<title> |
Always match by title (use this for titles that are pure digits) |
/send <file-path> |
Send a file from the workspace/inbox to WeChat |
/ls [path] |
List a computer directory |
/workspace |
Show the current workspace |
/help |
Show the command list again |
File transfer
- Inbound: images/files/videos sent from WeChat are downloaded, decrypted and saved to
<workspace>/.wechat-inbox/<date>/(name = original + message hash, stable naming prevents crash-replay duplicates;maxMediaBytescap, 100 MiB default). The model sees a[received file] <absolute path>hint and can continue with vision tools. - Outbound:
/send <path>sends directly; the agent can also put a single[[send-file:path]]line in its final reply (the line itself is never shown to the user). Paths must be inside the workspace or the inbox directory (one shared check; symlink escapes and out-of-root paths are rejected). - Voice messages stay rejected: not downloaded, not stored.
Proactive notifications
weixin_sendtool: agents in WeChat sessions can push text/files to WeChat (to the bound chat window; falls back tonotifyChatIdwhen unbound). Disable withenableWeixinSendTool: false.- Completion notifications: configure
notifyChatId+notifyOnTurnEnd: true, and when a task finishes in a session not bound to WeChat, a✅ Task complete: session「title」push goes to the notification target (bound sessions are never double-notified; deduped when the tool already pushed this turn).
Configuration (all optional)
Environment variables:
| Variable | Default | Meaning |
|---|---|---|
WEIXIN_BOT_TOKEN |
none | Login token (auto-saved after QR login; normally not needed) |
WEIXIN_ALLOWED_USERS |
the scanner | Allowed user ids, comma-separated |
WEIXIN_ALLOWED_GROUPS |
empty | Allowed group ids (groups need user+group match) |
WEIXIN_BOT_API_BASE |
https://ilinkai.weixin.qq.com |
iLink gateway |
WEIXIN_CDN_BASE |
https://novac2c.cdn.weixin.qq.com/c2c |
Media CDN |
WEIXIN_MAX_MESSAGE_CHARS |
3500 | Reply chunk length |
WEIXIN_MAX_MEDIA_BYTES |
100 MiB | Media size cap |
WEIXIN_PERMISSION_MODE |
full |
full = full permission; strict = reserved escape hatch |
WEIXIN_DSH_WORKSPACE |
auto | Default workspace for new WeChat sessions (this var > explicit config > dsh current workspace > process cwd) |
cordis config keys:
| Key | Default | Meaning |
|---|---|---|
inboxDir |
'' (=workspace/.wechat-inbox) | Inbox directory; out-of-root values fall back with a warning |
enableWeixinSendTool |
true |
Master switch for the weixin_send tool |
notifyChatId |
'' | Notification target / tool fallback (Web sessions can also push once set) |
notifyOnTurnEnd |
false |
Push completion notifications for unbound sessions |
logDir |
'' (=state dir) | Gateway log directory (gateway.log, 1 MB rotation) |
statePath |
~/.dsh/mobile-remote-weixin/gateway-state.json |
Gateway state file |
Health & logs
- Health snapshot (
/health): running state, poll activity, consecutive error count, binding counts, backlog, credential presence, start-failure reason — allowlisted fields only, never chat/session ids or progress. - File log:
gateway.log(append-only, 0600, 1 MB single-generation rotation, silent degradation on write failure), tee'd to the dsh logger.
Risks & boundaries (please read)
- Full-permission mode: no human in the loop; the allowlist is the only boundary — only add your own WeChat account.
weixin_sendoutbound surface: the tool is visible to in-scope agents; injected inbound messages could convince the model to push workspace text/files to WeChat.filePathis constrained by the same allowlist as/send, but text content is not path-checked — do not use in untrusted groups.- Privacy: messages transit Tencent iLink servers (not end-to-end encrypted); decrypted media lands in the workspace
.wechat-inbox. - Account coexistence: driving the same WeChat account with another iLink client (e.g. OpenClaw) will steal messages — disable one of them.
- Credentials: the token is stored locally (credentials service + managed fallback file, 0600); a leak equals account control.
- Platform risk: iLink is an undocumented bot API that may drift; rule-breaking use risks a ban — at your own risk.
Limitations & not-supported (honest disclosure)
- No voice recognition: voice messages always get「无法识别语音消息」(not downloaded/transcribed/stored) — a deliberate design decision
- No multimodal pipeline: images/files are only saved to disk with a path hint for the model; the plugin does not parse content (pair with a vision tool such as
vision_analyze) - No scheduled tasks: no cron-style "do X every day"
- No remote approval buttons: full-permission mode means no human-in-the-loop confirmations and no approve/reject interaction in WeChat;
strictmode is a reserved escape hatch (approval flow not implemented) - Depends on an undocumented protocol: iLink may drift and break features; misuse risks a ban
- Single account binding: one credential set per dsh instance; multiple WeChat accounts need multiple profile instances (no built-in multi-instance management)
- No content-level file dedup: resending the same file in different messages lands duplicate copies (only crash replays of the same message are deduplicated)
- Chinese-only commands and copy: slash commands, help text and prompts are Chinese; no English/i18n
- No graphical settings panel: all configuration is via environment variables / cordis patch (the login page only offers QR scan, a status bar and the health endpoint)
- Requirements: Node ≥ 22.12, a dsh web profile, and a WeChat account that can scan-bind an iLink bot
Development
npm install
npm run typecheck
npm test
npm run build
License
MIT
Links
More in this category
xmanrui/dsh-im★ 1548
Connect IM bots to DeepSeek Harness via QR codes or bot credentials (9 channels: Feishu, WeChat, DingTalk, WeCom, QQ, Slack, Telegram, Discord, and WhatsApp).
shaobeichen/dsh-pocket★ 1415
Remote phone access to the DSH Web UI: scan a QR code for LAN or public (cloudflared tunnel) access with real-time sync, a mobile-adaptive layout, and a settings tab.
inclusionAI/Avernet#deepseek-harness-channel-bcn★ 574
Connects DeepSeek Harness to Avernet's Bot Collaboration Network over WebSocket V2, with automatic onboarding, isolated agent sessions, tool-call events, and multi-bot routing tools.
omdsh-dev/dsh-notification★ 86
Desktop notifications for turn completions, with per-outcome controls and keyword rules.
whyihaveyou/dsh-suite#plugin-notify★ 57
IM webhook and local notifications on turn completion, errors, or approval (Feishu/WeCom/DingTalk/Slack/Discord/custom).
omdsh-dev/dsh-lark★ 55
Lark/Feishu bot channel for DeepSeek Harness: each chat drives its own agent, and tool approvals, model questions, and plan reviews return as cards answered by a button or a reply. Switch workspace and model from the chat (`/cd`, `/model`, `/new`), and run several bots that keep separate sessions and can hand turns to each other in one group.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.