Bundle
dsh-workspace-switch
Per-workspace activation control for DeepSeek Harness: turn individual skills, MCP servers, and plugins on or off for each workspace, from a dialog on the workspace row.
- Source
- liaoyuqing
- License
- MIT
- Updated
- Updated 13 days ago
Readme
# dsh-workspace-switch
Per-workspace activation control for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness):
each workspace decides which **plugins**, **MCP servers**, and **skills** its
sessions may use, and a dialog on the workspace row edits that decision.
English | [中文](README.zh.md)
## What it does
Two halves, one plugin:
- **Host half** (`index.js`, built to `lib/index.js`) reads the per-workspace
configuration when an Agent is created and applies it to that Agent's own
Cordis scope, so two Agents in two workspaces inside one harness process see
different capabilities:
- a disabled **skill** is shadowed in that scope by a same-name
non-invocable registration, which removes it from the model's skill
catalog;
- a disabled **MCP server** has every `mcp__<serverName>__*` tool denied in
that scope;
- a disabled **plugin** has the tool names its entry declares denied in that
scope.
The same half serves the configuration routes the dialog uses.
- **Browser half** (`src/client/`, built to `lib/client.js`) adds one row to a
workspace's `...` menu. It opens a dialog listing what the running
composition offers under each category, with a switch per capability.
A workspace with no entry inherits the deployment's composition unchanged, so
the plugin changes nothing until a workspace is configured.
## Configuration
Two sources describe one workspace, in increasing precedence:
1. `<DSH_HOME>/workspace-switch.json`, whose `workspaces` map is keyed by
workspace directory;
2. `<workspace>/.dsh/workspace-switch.json`, which replaces the shared entry
for that workspace when it exists.
```json
{
"workspaces": {
"E:\\my_project\\godot-game": {
"plugins": { "mcp-godot-ai": { "enabled": false, "tools": ["mcp__godot-ai__run"] } },
"mcp": { "godot-ai": { "enabled": false } },
"skills": { "godot-scene-authoring": { "enabled": false } }
}
}
}
```
`enabled: false` switches a capability off for that workspace; an absent entry
means enabled. A plugin entry also declares the **tool names** the plugin
registers — the gate denies tools by name, so a plugin without `tools` has
nothing to deny.
The dialog writes the document that currently answers for the workspace: the
project file while one exists, the shared store otherwise. Output is published
through a temp-file rename, so a reader never sees a half-written document.
## Install
The plugin is a DSH bundle: add it to a profile and select it.
```sh
dsh plugin add link:/path/to/dsh_workspace_switch
```
then add `dsh-workspace-switch` to the profile's `dsh.profile.bundles`. A new
bundle row loads at the next harness start.
## Build
The browser half is a DSH client bundle and must be built; the repository
toolchain is required (the plugin vendors its copy of the client build preset at
`scripts/tsdown.client.ts`, which resolves the harness sources from the checkout
it sits in).
```sh
# from a deepseek-harness checkout
pnpm exec tsdown --config dsh_workspace_switch/tsdown.config.ts # or, inside the plugin: pnpm build
pnpm exec tsc -p dsh_workspace_switch/tsconfig.typecheck.json # typecheck the browser half
node --test "tests/**/*.test.js" # unit tests
```
**`lib/` is committed.** The package's `main` and `./client` both point into it,
and a clone has neither the harness sources nor a build toolchain, so a
build-from-source install (`dsh plugin add github:…`) would otherwise install a
package with no entry points. Commit the rebuilt files with any change that
alters them.
A standalone clone cannot run the build: the vendored preset imports the harness
sources (`../../packages/…`, `../../scripts/…`) that only exist inside a
checkout. Build inside the checkout, then commit `lib/` here.
## Known limitations
- **Skills are gated, not unloaded** — a disabled skill keeps its files on
disk; only its catalog entry and loading are removed for that workspace.
- **A plugin needs declared tools** — the gate denies tools by name, so
switching a plugin off only removes what its entry names in `tools`.
- **The dialog lists what the Host can address** — plugin rows come from the
profile's plugin manager (or the read-only inventory); a capability the
composition does not expose cannot be configured.
## Licence
MIT.Install
dsh plugin --profile web add github:liaoyuqing/dsh_workspace_switch
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-workspace-switch from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.