DSH Plugins Marketplace

DSH Plugins

Plugins

/

Tools & Capabilities

/

dsh-sync

R

dsh-sync

Manifest valid

DeepSeek Harness plugin: sync sessions and profile configuration across machines with rclone bisync, with a configurable sync scope and guided WebDAV setup.

UI (client)hasBundlePatch

dsh-sync

A DeepSeek Harness plugin that adds a Settings → Sync page for carrying one machine's DSH home directory (~/.dsh) to other machines: session logs and profile configuration, synced bidirectionally through any rclone remote.

It wraps rclone bisync so that none of the following has to be done by hand: editing rclone filter files, remembering the --resync seeding order, or running rclone config interactively.

What the page does

AreaPurpose
Current stateWhether rclone is installed, the resolved local and working directories, the generated rules file, the last run, and how many conflict copies exist
Sync targetEither a cloud remote picked from rclone listremotes plus a subpath, or an absolute local folder that a provider client already syncs
Connection self-testReachability, writability, and modification-time fidelity of the target, before anything is seeded
Sync scopePer-slice toggles for what travels between machines, extra exclusion rules, comparison mode, conflict handling, deletion ceiling
Configure cloud storageCreates a WebDAV remote non-interactively, with a Nutstore (坚果云) preset
ActionsPreview changes (--dry-run), sync now, first-time seed (--resync)
Run outputThe full rclone output, also appended to logs/ui-<date>.log
Conflict copiesEvery *.conflictN file left behind, so it can be merged by hand

The connection self-test

Run this before the first seed, and after changing remotes. It uploads one temporary file through the configured remote, reads its metadata back, and removes it — so the credential never leaves rclone's own configuration.

StepWhat it provesWhat a failure means
ReachabilityThe remote answers an authenticated listingWrong URL, wrong account, no network, or a bridge process that is not running
WritabilityA file can be uploadedThe account is read-only, or the server gates writes behind a permission it lacks
Content checkThe upload read back at the expected sizeThe transfer path corrupts data
Modification timeThe remote returned the time the file was sent withA two-way sync will misread every run

The last step is the one that cannot be inferred from any documentation. bisync compares size,modtime against the previous run's listing, so a remote that replaces the modification time with the upload time makes both sides look changed on every pass: files are retransferred, and conflict copies accumulate. The probe dates its file to a fixed past instant, which is far enough from "now" to be unambiguous.

When the remote rewrites modification times the verdict says so, recommends size, and offers to apply it. Take that recommendation deliberately rather than silently: size alone cannot detect an edit that leaves the file the same length.

npm test   # includes both probe suites

Syncing through a cloud provider's own client

A target does not have to be an rclone remote. An absolute local folder works too, which lets a cloud provider's own desktop client do the cloud transport:

~/.dsh  ──rclone bisync──▶  <mirror folder>  ──provider client──▶  cloud

Set Target type to Local folder and point it at the folder the provider client already syncs. Nothing else changes: the same filter rules, conflict copies, preview, and deletion ceiling apply, and the self-test runs against the folder.

This is the better path for providers rclone cannot reach directly (百度网盘, 夸克网盘). It avoids a reverse-engineered WebDAV bridge entirely — no cookie to extract, no WebDAV write permission to discover, no unmaintained driver.

What it costs:

  • Two sync layers in series. A failure is either bisync's or the client's, and you have to tell them apart.
  • The cloud layer's conflicts are the provider's business. rclone's .conflictN naming applies between the home directory and the mirror; above that the provider client decides, and whatever artifact it leaves becomes a new file the outer layer copies into ~/.dsh.
  • Modification times may drift. A client that stamps downloads with the current time makes bisync take one extra, content-identical pass per file. It settles rather than thrashing, because both sides of the bisync pair are local filesystems.

Why a mirror, and not the home directory itself

Pointing DSH_HOME straight at a folder the provider client syncs looks simpler and is worse:

  • storages/ must not be shared. workspace.json is rewritten wholesale by each machine; two writers overwrite each other and sessions disappear from the sidebar. Consumer sync clients generally cannot exclude a subfolder.
  • .credentials.yaml holds plaintext API keys, with the same lack of exclusions.
  • session.lock and *.tmp are per-machine artifacts.
  • Session logs are appended to constantly, and a client that uploads a file mid-write handles that badly.
  • No preview, no deletion ceiling, no conflict copies. rclone's safety rails are what make the exclusions above trustworthy in the first place.

Mirroring through bisync keeps every one of those rules in force, because the filter rules run before anything reaches the provider client.

Install

The plugin is an ordinary DSH bundle. Author or unpack it anywhere on disk, then install it into a profile:

plugin_manager install_bundle  target: <absolute path to this directory>

Installing links the directory into the profile and enables the bundle. Restart the dsh web server afterwards: the Cordis loader caches the module path it resolved for an entry, so a replaced or relocated plugin keeps running the previous JavaScript module generation until the process restarts. Changing a directory or a row id does not bypass that cache.

rclone visibility on Windows

The plugin runs rclone and reports it as missing when it cannot be found. On Windows, PATH alone is an unreliable answer: a process started before the winget install inherits an environment without winget's command-shim directory, and a new terminal launched from a long-running explorer.exe inherits that same stale environment. Restarting dsh web in the same terminal therefore does not help.

The plugin resolves the executable once per process, trying PATH first and then %LOCALAPPDATA%\Microsoft\WinGet\Links. The status card shows the path it settled on, so a fallback is visible rather than silent. If rclone lives somewhere else entirely, put its directory on PATH for the process that launches dsh web.

Configuration

Settings live in <workDir>/settings.json and are written by the page. They are a plain JSON document:

{
  "version": 1,
  "target": "nutstore:dsh",
  "sync": {
    "sessions": true,
    "attachments": true,
    "profiles": true,
    "homeConfig": true,
    "credentials": false,
    "workspaceState": false,
    "providerCache": false,
    "pluginModules": false
  },
  "extraExcludes": [],
  "compare": "size,modtime",
  "conflictResolve": "none",
  "maxDelete": 10
}

The loader row's config seeds the two paths that must be known before the settings file can be found:

- id: dsh-sync
  name: '@local/dsh-sync'
  config:
    localRoot: /home/me/.dsh   # default: $DSH_HOME, then ~/.dsh
    workDir: /home/me/.dsh-sync # default: ~/.dsh-sync

Why settings are not a Config schema

A bundle installed outside a profile cannot resolve @deepseek-ai/schemastery, so it cannot export the validated Config schema the harness expects. The settings file replaces it and the page is the editing surface. A deployment that installs this bundle from inside a profile can switch to a schema-backed Config without changing the route contract.

Sync scope

Each slice maps to rclone filter rules emitted when the slice is disabled:

KeyContentDefault
sessionssessions/** — one append-only log per sessionon
attachmentsattachments/** — images and files a session referenceson
profilesprofiles/** — bundles, patch layers, lockfileson
homeConfigcordis.patch.yml, AGENTS.md at the home rooton
credentials.credentials.yaml, .env — plaintext API keysoff
workspaceStatestorages/** — sidebar grouping and derived cachesoff
providerCachellm-deepseek/** — expiring vendor upload recordsoff
pluginModulesnode_modules/** — platform-specific binaries and absolute linksoff

/.anonymous-user-id, session.lock, and *.tmp are always excluded.

The rules file is generated; editing it by hand has no effect, because the next state read rewrites it from the settings. Changing settings also invalidates bisync's remembered filter hash, which is why the page regenerates it before every run.

Nutstore (坚果云) and other WebDAV servers

The page creates the remote through rclone obscure followed by rclone config create, so the interactive rclone config flow is never needed.

For Nutstore: URL https://dav.jianguoyun.com/dav/, vendor other, and an app password generated under Account information → Security options → Add app password. The login password does not work over WebDAV.

Two properties of plain WebDAV matter for bisync:

  • Modification times. rclone reports modified times only for Fastmail Files, ownCloud, and Nextcloud. On a plain WebDAV server the remote copy's modification time is the upload time, which can make bisync see spurious changes. Start with the default size,modtime; if a preview lists a large number of changes on an otherwise idle tree, switch Change comparison to size.
  • Hashes. Plain WebDAV reports none, so checksum comparison would require downloading every file. It is deliberately not offered as a comparison mode.

The password is passed to rclone obscure as a process argument, so it is briefly visible to a local process listing. It is never written to the settings file or the logs, and the obscured value is redacted from everything returned to the browser.

Seeding order

--resync makes both sides a superset: a file present on only one side always survives. Only a file present on both sides with different content needs a winner, chosen by the resync mode.

  1. On the machine holding the most complete state, run First-time seed with winner path1 (local wins). The remote is empty, so nothing can be lost.
  2. On every other machine, run First-time seed with winner path2 (remote wins). That machine's unique sessions are uploaded, and its same-named configuration files are replaced by the cloud copy — which is what "keep the machines consistent" means.
  3. Afterwards use Sync now. --resync is only for a first pairing, a changed rules file, or recovery from a failed run; using it routinely resurrects deleted files.

Preview every seed with Preview changes first.

Operating constraints

  • Do not continue the same session on two machines. Session logs are append-only; two writers diverge and the sync can only leave a conflict copy.
  • Keep project paths identical across machines. A session header records the absolute cwd it was created in, and the sidebar groups sessions by it. A session copied to a machine without that path is grouped under a workspace path that does not exist there.
  • Host-side edits need a server restart — see Install.

Routes

All five are exact Fetch routes under /api/, so Connection applies its Host/Origin checks and browser authentication. The browser addresses them document-relative, without the leading slash.

RouteMethodBodyReturns
/api/dsh-sync.stateGET—Settings, sync-scope catalogue, rclone state, last run, conflicts
/api/dsh-sync.settingsPOSTPartial settings{ ok, settings }
/api/dsh-sync.remotePOST{ name, url, user, pass, vendor }{ ok, remote, output }
/api/dsh-sync.probePOST{ target }{ ok, target, steps, verdict, recommendedCompare, hashes }
/api/dsh-sync.runPOST{ action, target, resyncMode }{ ok, exitCode, output }

action is preview, sync, or seed. A probe verdict is one of ok, modtime-mismatch, unreachable, read-only, or partial.

Development

There is no build step: the Host half is plain ESM and the Client half is a plain-JavaScript module-loader factory.

node --check index.js && node --check client.js   # syntax
npm test                                          # all four suites
SuiteCoversNeeds
test/host-routes.mjsBuilds a stub Context whose connection.fetch.register records routes, calls apply(ctx, { localRoot, workDir }) with both paths redirected into a temporary directory, then invokes every route with a real Request. It never touches a real DSH home.nothing
test/dictionaries.mjsBoth dictionaries define the same keys, every t('...') call resolves, the indirectly referenced ITEM_TEXT labels exist, and every step id and verdict the Host can emit has a label.nothing
test/probe-round-trip.mjsRuns the self-test against an rclone-served WebDAV peer over loopback and asserts a healthy verdict. Sets RCLONE_CONFIG to a temporary file, so the user's own remotes are untouched.rclone (found on PATH or in winget's shim directory)
test/probe-modtime-mismatch.mjsRuns the self-test against a minimal WebDAV server that deliberately reports the wrong modification time, and asserts the probe catches it and recommends size.rclone (found on PATH or in winget's shim directory)

The two probe suites skip with a printed reason when rclone is absent, so npm test stays green on a machine that has not installed it yet. All four locate rclone the same way the plugin does — PATH first, then winget's command-shim directory — so they run on a machine whose PATH predates the rclone install.

License

MIT — see LICENSE.

Comments

Loading…

From the same category

reactive-resume

DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.

Tools & CapabilitiesManifest valid

★ 41.7k

↓ 270/wk

MIT

Aug 24, 2026

dsh plugin --profile web add dsh-plugin-reactive-resume

by Tencent

Let AI agents use your real, logged-in browser without interrupting your work. CLI + extension for browser automation across any shell-capable AI agent.

Tools & CapabilitiesManifest valid

★ 8.1k

↓ 7k/wk

MIT

TypeScript

Sep 30, 2026

dsh plugin --profile terminal add @wxg-prc-cpg/browser-skill-dsh-plugin

by yjh051108

dsh-routing-suite — injector + router-standard kit: install the runtime injector first, then the task-aware reasoning-mode router preset (measured P1-P23).

Tools & CapabilitiesManifest valid

★ 7k

MIT

JavaScript

Sep 18, 2026

dsh plugin --profile web add @dsh-external/dsh-super-injector

by Q00

Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CLI, Gemini CLI, OpenCode,

Tools & CapabilitiesManifest valid

★ 6.2k

MIT

Python

Oct 4, 2026

Index only — not installable

by dsh-market

The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场

Tools & CapabilitiesManifest valid

★ 5.4k

↓ 164.4k/wk

MIT

TypeScript

Oct 3, 2026

dsh plugin --profile web add dshmarket

by superdesigndev

OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn

Tools & CapabilitiesManifest valid

★ 4.1k

NOASSERTION

Python

Oct 4, 2026

dsh plugin --profile web add treg-dsh