Send files or folders over the local network via the LocalSend v2 protocol, or generate a temporary browser download link that the receiver opens with no software installed.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:huangfuren/dsh-localsend
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
English | 中文
LAN file/folder transfer plus browser download-link sharing: let DeepSeek Harness send files (or folders, auto-packed into a zip) over the conversation to any machine on the same LAN running LocalSend, or generate a browser download link (the receiver installs nothing).
Zero configuration by default — the LocalSend and share channels need no credentials, there are no third-party runtime dependencies and no hard-coded paths — it detects the local NIC subnet automatically and uses the hostname as the sender alias, so it works the moment it is installed. Ships host tools (for the agent) and a browser settings card (for the UI).
Current version: 0.5.0. Compatible with DeepSeek Harness 0.1.x and 0.2.0-rc.1 (peer range
>=0.1.0-rc.6 <1.0.0); Node.js ≥ 22.19; supports Windows / macOS / Linux.
How it works
LocalSend mode (localsend_send_files)
LocalSend has no official CLI, but every LocalSend receiver is a standard HTTP(S) service (default TCP 53317, self-signed certificate) speaking the public LocalSend Protocol v2. This plugin implements the sender:
- Discover: probe
GET /api/localsend/v2/infowithin the active subnet (read-only), matching by alias or IP; - Negotiate:
POST /api/localsend/v2/prepare-uploadsubmits metadata (name/size/type/sha256) — the receiver pops a dialog for the user to accept; - Upload:
POST /api/localsend/v2/uploadsends the raw bytes; the receiver verifies by sha256.
Directories need no manual packing: a built-in zero-dependency zip writer packs a folder into <folder>.zip before sending and cleans up the temporary archive afterwards.
Share mode (localsend_share)
The receiver installs nothing. The plugin starts a temporary HTTP server on this machine and produces a one-shot download link:
- Directories are auto-packed into a zip; small files (≤64 MB) get a sha256;
- A URL with a random token is generated — the receiver opens it in any browser and downloads;
- Once every file has been downloaded, or the link expires, the server shuts itself down.
Optional password protection (HTTP Basic Auth) and configurable port / lifetime are supported.
SMB push mode (localsend_smb_push)
When the receiver installs nothing at all, push files/folders over an SMB share automatically into a specific directory on the target machine: target (IP/hostname) + share (share name) + destDir (subdirectory under the share; empty = share root) + files; username/password optional (anonymous = guest). Directories are auto-packed into a zip before copy. Prerequisite: the receiver pre-creates a share and grants the sender write access. This is the only workable channel for "no software + specific IP + specific destination directory + fully automatic" (the LocalSend channel forces the receiver to install the app; the browser-link channel cannot name a destination directory).
Target profiles (recommended) — save one profile per target machine in the settings card (name / target IP / share / sub-directory / account / password). Afterwards a call only needs profile="书房台式机" plus files; the profile supplies everything else, and any explicit argument overrides the matching field. That turns "push this local folder to the desktop of that machine" from "retype five parameters every time" into "configure once + one command". To land on the desktop, use share="C$" + destDir="Users\<user>\Desktop" (C$ is the admin share, present by default on Windows).
Boundary: a profile only stores how to reach the channel; it cannot create one. The receiver still needs a one-time access channel — the admin share
C$exists by default (if the target account is a Microsoft account and not the built-in Administrator, setLocalAccountTokenFilterPolicy=1once), or a custom share with write access for the sender. After that, every push needs zero action on the receiver.
Features
- Five tools:
localsend_list_devices— scan the LAN and list LocalSend devices (ip / alias / protocol version / device type); optionalsubnet(CIDR) to scope the scan;localsend_send_files— send files/folders to a named target (alias auto-resolved, or IP); directories auto-packed; probes the target first, so a wrong IP fails in seconds with next steps instead of waiting out the accept timeout; blocks until the receiver accepts, then uploads, returning per-file results;localsend_share— generate a temporary LAN HTTP download link; the receiver just opens it in a browser, no software needed; supports password protection; the server closes after download; output is a structured object (url / per-file size / total size / expiry / whether password-protected / log);localsend_send_plugin— pack a DSH plugin directory into a self-contained distribution zip (excludesnode_modules/.git; contains adsh-plugin.manifest.jsonmanifest +INSTALL.mdcard) and share it over a temporary HTTP link; the receiver needs only a browser, no LocalSend or any software, then unzips and runs one install command fromINSTALL.md. Thepluginargument accepts an absolute directory path or an installed plugin name (resolved read-only under~/.dsh/profiles/*/node_modules; distributing dsh-localsend itself is justplugin="dsh-localsend");localsend_smb_push— see "SMB push mode" above.
- Mixed files and folders: one list may hold both files and directories; each directory is packed into its own zip.
- GUI settings card: the "LocalSend LAN transfer" card under Settings → plugin configuration, editing alias / port / timeouts / max file size / share port / expiry / password, and adding/removing target profiles (including credentials); saving takes effect immediately (for new sessions' tool calls).
- Robustness: duplicate/ambiguous aliases are flagged; error codes (403 refused, 409 busy, 429 rate-limited, 422 verification failed, …) map to readable text; failures cancel the session; symlinks and empty directories are skipped; the per-file/per-package cap defaults to 1 GiB (configurable).
- Secure by default: LAN only; scans are read-only; the sender alias defaults to the hostname; the receiver's manual "accept" is the authorization gate; self-signed HTTPS + end-to-end sha256; the share link is one-shot (random token).
- Works out of the box / distributable: no build step (
index.js/client.jsare the artifacts), no machine-local path residue; installable viadsh plugin,npm pack, or a manual link.
Installation
Recommended: DSH-managed install (published on GitHub)
dsh plugin --profile web add git+https://github.com/huangfuren/dsh-localsend.git#v0.5.0
#v0.5.0 pins that release; drop the suffix to track the latest commit on main. After installing, restart DSH: new sessions gain the five tools, and after the GUI refreshes the card appears under Settings → plugin configuration.
Local / offline install
- Put the
dsh-localsenddirectory into your plugin folder (e.g.dsh-plugin\); - Add
"dsh-localsend": "file:<path>"(orlink:<absolute path>) to the profile'spackage.jsondependencies, and adddsh-localsendtodsh.profile.bundles; - Or run
npm packon the directory and, in the profile directory,npm/pnpm install <dsh-localsend-0.5.0.tgz>(network needed to resolve peers); - Restart DSH.
Configuration (GUI card / settings namespace localsend)
| Key | Default | Description |
|---|---|---|
alias |
auto (hostname) | Sender alias seen by the receiver |
port |
53317 | Target LocalSend port |
scanTimeoutMs |
1500 | Per-IP probe timeout (ms) |
acceptTimeoutMs |
240000 | Wait for the receiver to accept (ms) |
uploadTimeoutMs |
120000 | Per-file upload timeout (ms) |
maxFileBytes |
1073741824 (1 GiB) | Per-file/per-zip size cap (bytes); folders are zipped in a streaming pass, so memory tracks the largest single file rather than the folder total |
sharePort |
0 | Share server port (0 = random) |
shareExpiresIn |
3600 | Share link lifetime (seconds), 0 = no expiry |
sharePassword |
"" | Share download password (empty = none) |
smbProfiles |
[] |
Array of target profiles, each {name, host, share, destDir, username, password}; once saved, localsend_smb_push only needs profile="<name>" (credentials are stored in plain text — see Security notes) |
dshProfileDir |
~/.dsh |
DSH home used to resolve installed plugins by name (read-only) |
All keys may be left default; empty means the built-in default.
sharePort / shareExpiresIn / sharePassword also act as the defaults for the matching tool
arguments of localsend_share and localsend_send_plugin: omit an argument and the setting applies,
pass it explicitly and the argument wins (including expiresIn=0 for "no expiry" and password=""
for "no password this time").
Examples
LocalSend mode
Pack the
D:\资料\报告folder and send it to 黄夫人 SendC:\tmp\a.pdfandD:\photosto 192.168.1.50
The tool resolves the target (exact/ambiguous alias match or IP) → packs directories into a zip → asks the receiver to accept → uploads → reports per-file results. If the receiver has not enabled auto-accept, someone must tap "accept" in their LocalSend.
Share mode
Share
D:\资料\报告.pdfwith a colleague Generate a download link with password 1234
The tool generates a temporary HTTP download link; the receiver opens it in a browser and downloads — no software needed.
SMB push
Push
D:\打包\bundleto the dsh-sync directory under the "共享文件夹" share on 10.0.0.30 PushD:\打包\bundleto the desktop of "书房台式机"
The tool packs the directory and copies it automatically into the named directory of the target share, with no "accept" on the receiving side, provided the receiver has opened the share and granted write access. The second example uses a target profile: configure "书房台式机" once as C$ + Users\<user>\Desktop, then every later push is a single sentence.
Security notes
- LAN only; the scan never leaves the local active subnet or crosses a gateway.
- Probes are read-only (
info); a send must be "a target the user named explicitly + files/folders the user named explicitly". - The receiver must tap "accept" by default (or has auto-accept on); the protocol has no shared secret, so the dialog is the authorization gate.
- The sender only holds file contents; it reads and stores no credentials, and treats every receiver response as untrusted data.
- Exception — SMB target profiles: if you save profiles in the settings card, their credentials (including the password) are stored in plain text in the local DSH settings file and travel with it whenever it is synced or backed up. This is a deliberate trade-off for pushing between your own machines — do not enable it on a shared or multi-user machine.
- LAN transfer uses self-signed HTTPS; a sha256 mismatch (HTTP 422) surfaces a clear error.
- The share link is a one-shot random token; the server closes after download; password protection is optional.
Development and testing
npm run check # node --check on every entry point
npm test # unit tests + a local mock-receiver end-to-end (zip packing, upload, 422 mismatch, cancel), no network
npm run verify
Coverage: zip write/parse round-trip, CRC-32, directory packing and cleanup, mock end-to-end "directory → auto zip → upload", sha256 mismatch 422, session cancel, SMB UNC building with net use/robocopy arguments (including a regression case asserting the target appears exactly once), and target-profile resolution (findProfile lookup/error, mergeProfile's "explicit args override the profile").
Compatibility notes
- The peer range is deliberately wide (
>=0.1.0-rc.6 <1.0.0); both the dsh 0.1.x line and 0.2.0-rc.1 resolve. - Verified against the host's
ctx.tools/systemPrompt/settingsand the client's keyed slot anddsh.client.inject. - Anything outside that range is uncertified.
Release
- Repository: https://github.com/huangfuren/dsh-localsend
- Suggested flow: pass all tests (
npm run verify) →npm pack→ tag a GitHub Release (attach the tarball).
License
Links
More in this category
Tencent/WeKnora#dsh-weknora★ 35688
Four read-only tools over a WeKnora knowledge base: list knowledge bases, hybrid passage search, reassemble one document's chunks in order, and WeKnora's own cited RAG or ReAct-agent answer with a resumable session id.
superdesigndev/treg★ 6403
Tool catalog for agents: search ~2,600 external endpoints (SEO and SERP, backlinks, social, people and company enrichment, ad libraries, scraping) by the task you want done, read each one's parameters and per-call price, then call it with the credential injected server-side. Ships the skill plus an MCP row that stays disabled until TREG_TOKEN is set.
T-Auto/dsh-ops★ 4593
Provides bash, PowerShell 7, and high-performance Rust tools for DSH on Windows to reduce token usage.
sixtysevenlf/dsh-blender-plugin★ 1388
Lets a DSH agent drive a local Blender over a direct TCP channel with 15 tools: viewport frames, custom-angle renders, Python execution, headless and job offload, transaction rollback, and a planning layer of 228 ops across 34 families.
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1152
Tencent CloudBase backend for DeepSeek Harness — scaffold and deploy full-stack apps from chat, render query results as table cards with paging, sorting and CSV export, preview a deployment on its domain, and call the CloudBase MCP toolset (`mcp__cloudbase__*`) with device-code login.
anysearch-team/anysearch-dsh★ 665
AnySearch-powered real-time web and vertical search provider for DeepSeek Harness.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.