dsh-virtual-workspace
> 📖 简体中文 | English
> Virtual Workspaces for DeepSeek Harness (DSH) — a dynamic Cordis Plugin that lets the agent read, search and modify code and files across multiple project directories at once.
✨ Features
- Virtual workspaces:
name → multiple project directoriesmapping groups — define once, use everywhere. vwsagent tool (13 actions):list / add / remove / add-dir / remove-dir / set-mirror / resolve / read / write / edit / ls / find / grep, withname:/relative/pathsyntax — files resolve to the first existing match, directory operations take the union.- Native sidebar integration: takes over the built-in + add-workspace button in the sidebar header and opens a dropdown drawer — create a regular workspace with the system folder dialog (native behavior) or a virtual workspace from multiple directories, and manage existing workspaces right in the drawer.
- Mirrored into the official list: member directories are auto-registered as built-in workspace entries (titled
Workspace · Directory) in the sidebar workspace/session list; only entries created by this plugin are removed (ownership tracking). - Sandbox-consistent: reads are unrestricted; writes/edits follow the calling session's sandbox boundary, and out-of-boundary writes can be retried once with user approval (
sandbox_permissions + justification, the same mechanism as the built-in write tool). - Global awareness: the tool and the prompt section are registered on the root context, so agents in any session (including sessions opened under mirrored directories) can call
vwsand see the workspace list. - i18n: UI supports Simplified Chinese (zh) and English (en); zh shows Chinese, every other language falls back to English; language switches apply instantly.
- Persistent: definitions are saved to
<deployment workspace root>/.vws-workspaces.jsonand restored automatically after restarts.
📷 Screenshots
1. The drawer opened by the + button
> !image-20260814155305458 > > !image-20260814155313460
2. Mirrored entries in the built-in sidebar
> > > !image-20260814155626728
3. The system folder picker dialog
> !image-20260814160008485 > >
4. Agent using vws across projects in a conversation
> >
📦 Official install (bundle, permanent)
This repository is also an official bundle-format plugin package (package.json declares dsh.bundle → cordis.patch.yml + index.js), installable straight from GitHub and booted permanently with a profile:
dsh plugin --profile <name> add github:KevinWen7415/dsh-virtual-workspace
dsh --profile <name>- The package is plain JavaScript with no build step, so the pnpm
allowBuildsapproval that the official docs require for TypeScript packages is not needed; - Uninstall:
dsh plugin --profile <name> remove dsh-virtual-workspace; - The bundle ships both Host and Client: the
vwstool, the prompt section, mirror registration, state persistence, sandbox escalation, and the sidebar + drawer UI (since v1.2.0, via thedsh.clientdeclaration and same-origin/api/vwsroutes) — feature-complete versus the dynamic version; - Compared to the dynamic install: a bundle loads automatically after process restarts and depends on no session.
🚀 Installation Tutorial (dynamic plugin)
This plugin is a dynamic Cordis Plugin: it runs inside the DSH process and is defined/activated via the built-in cordis_* tools — no build step.
0. Prerequisites
- DeepSeek Harness (DSH) deployed and running, with the Web UI reachable (e.g.
http://127.0.0.1:3080); - At least one open session;
- GitHub access (recommended); otherwise clone locally first:
git clone https://github.com/KevinWen7415/dsh-virtual-workspace.
1. Prepare the code
The source lives at https://github.com/KevinWen7415/dsh-virtual-workspace (public repo — the agent can read it directly, no clone needed).
src/host.js and src/client.js each export a function (export default function () { … }); the return { … } body inside is what goes into code.host / code.client of cordis_define.
2. Install (recommended: hand the GitHub URL to the agent)
Open a DSH session and send one sentence:
Please auto-install the plugin from this repo: https://github.com/KevinWen7415/dsh-virtual-workspace
(read src/host.js and src/client.js, define it with cordis_define, then activate with cordis_run)The agent reads the two source files and completes cordis_define → cordis_run by itself; then:
1. If an approval prompt appears on the page (awaiting-approval), click Allow (required for the first package with a browser UI); 2. Once you receive the success notification, refresh the page.
> If the DSH machine cannot reach GitHub: clone locally first with git clone https://github.com/KevinWen7415/dsh-virtual-workspace, then send "please install the plugin at <local clone path>" — the remaining steps are the same. > Security note: only install repos you trust.
2′. Install (manual tool calls)
1. Call cordis_define: - plugin: { "kind": "new", "idPrefix": "vws" } - name / purpose: anything, e.g. Virtual Workspaces - code.host: paste the whole return { … } body between export default function () { and the trailing } in src/host.js - code.client: likewise, take the function body from src/client.js 2. Note the returned pluginId / packageId; 3. Call cordis_run: { "pluginId": "…", "packageId": "…", "mode": "run" }; 4. After approval and the success notification, refresh the page.
3. Verify the installation
- Click the built-in + in the sidebar header → the Virtual Workspaces drawer drops down;
- Add a workspace in the drawer (name + one directory per line) →
Name · Directorymirror entries appear in the built-in sidebar list; - In the conversation, ask the agent to "list virtual workspaces with
vws list" — it should return the status JSON.
4. Daily usage
- UI: add/remove workspaces in the drawer,
Sidebar: on/offmirror toggle, per-directory ×; the panel can be dragged by its header; - Agent: just say "read
EDB:/src/xxx", "search xxx in EDB", or "change xxx to yyy in EDB"; when a write goes outside the session boundary the agent asks for escalation — approve it and the one-shot write completes.
5. Update / Stop / Uninstall
| Operation | How |
|---|---|
| Update | cordis_define with kind:"existing" and the same pluginId to append a new package → cordis_run mode:"update" |
| Roll back | cordis_run mode:"run" with the currentPackageId |
| Stop (keep definitions) | cordis_stop |
| Uninstall | ① first remove workspaces or turn mirroring off in the drawer (cleans mirror entries from the built-in list) ② cordis_stop ③ cordis_undefine |
6. FAQ (installation)
- Activation fails with
Failed to fetch: a transient network issue — just retrycordis_run(or refresh the page and retry); no code changes needed; - After a DSH process restart: reactivate the plugin (
cordis_runwith the originalpluginId; the definition is kept and workspace definitions persist); - Mirror entries remain after uninstall: registry records are durable; if not cleaned before uninstalling, remove them manually in the built-in sidebar;
- Approval rejected: there is no automatic retry; start
cordis_runagain manually when needed; - Installing from the GitHub URL:
github.com/KevinWen7415/dsh-virtual-workspaceis a public repo; DSH needs GitHub access (or use a local clone path); the first activation still requires page approval.
> Code constraints (platform requirements): plain JavaScript only, no import/require/JSX/TypeScript; Client code must use React.createElement; all file operations must go through the ctx.fs service. See docs/03-development.md.
> Note: a dynamic plugin lives with the DSH process. To make it permanently built in and session-independent, bake it into the host composition (see the roadmap in docs/02-design.md).
📂 Repository Structure
dsh-virtual-workspace/
├── README.md # 简体中文说明
├── README.en.md # English README (this file)
├── LICENSE # MIT
├── package.json # dsh.bundle manifest + metadata
├── cordis.patch.yml # bundle patch layer (official install entry)
├── index.js # static Host plugin (bundle entry, no build)
├── src/
│ ├── host.js # dynamic Host half (code.host)
│ └── client.js # dynamic Client half: built-in + drawer panel UI (code.client)
└── docs/
├── 01-requirements.md # Requirements (user feedback, functional/non-functional requirements, acceptance)
├── 02-design.md # Design (slot selection, mirror registration, drawer design, cross-session scope)
├── 03-development.md # Development (code structure, release flow, debugging, conventions)
├── 04-api-reference.md # API reference (tool/RPC/state file/error codes)
├── 05-testing.md # Testing (cases, regression checklist, known limitations)
└── images/ # Screenshot directory (see the table above)🧭 Key Concepts
| Concept | Description |
|---|---|
| Virtual path | name:/relative/path: resolved across every member directory; files take the first match, directory operations take the union |
| Mirror | Member directories registered into the built-in workspaceRegistry, titled Name · Directory; the plugin only removes entries it created |
| Sandbox | Reads unrestricted; writes follow the session boundary; out-of-boundary writes can be escalated once with sandbox_permissions (user approval) |
| Scope | Tool and prompt section are registered globally — agents in all sessions can use vws |
❓ FAQ
- Why aren't virtual workspaces in the built-in list? The built-in list is driven by
workspaceRegistry, which only accepts real, existing directories ("fake directories" are rejected). This plugin solves it via mirror registration: member directories appear in the official list asName · Directory. - Can other sessions modify files across workspaces? Yes:
vwsis globally available and reads are unrestricted; writes follow each session's boundary, and cross-directory writes go through one-shot approval escalation. - Where is state stored?
<deployment workspace root>/.vws-workspaces.json(local example:C:\Users\<user>\.vws-workspaces.json).
📚 Version History
| Package | Description |
|---|---|
| pkg-1 | Initial: tool/service/RPC + settings page |
| pkg-2 | Writes always stamped with the calling session's sandbox policy (consistent with the built-in fs tools) |
| pkg-3 | Removed the settings page; floating sidebar button + management panel |
| pkg-4 | Mirror registration into the built-in sidebar (toggle / ownership tracking / safe cleanup) |
| pkg-5 | Removed the floating button; took over the built-in + flow (native single directory + multi-directory creation/management) |
| pkg-6 | Drawer form: fixed-position drop-down panel (animation + own scrolling), fixing the slot height limit |
| pkg-7 | i18n: registered en/zh dictionaries; zh shows Simplified Chinese, other languages fall back to English, instant switching |
| pkg-8 | Fix: drawer froze after closing the system folder dialog (picking no longer disables the whole drawer, Cancel always clickable, reset on reopen) |
| pkg-9 (current dynamic) | Draggable drawer: drag by the header (element-level pointer capture, no global listeners), grab/grabbing cursor feedback |
| bundle v1.2.0 | Official bundle format (Host + Client): permanent install via dsh plugin add github:KevinWen7415/dsh-virtual-workspace, including the drawer UI |
📄 License
[MIT](LICENSE)