dsh-skill-preferences
Manage DeepSeek Harness (DSH) skills in Settings → Skills, with global, user, and workspace preferences.
简体中文
Version and compatibility
0.2.2 restricts the global selector and global writes to the host's administrator role. It replaces 0.2.1's default-open adminUsers allowlist. Version 0.2.1 fixed the plugin's response-schema mismatch and the display of layer-specific switches.
The plugin uses public WebServer, Auth, settings, skills, Agent, and client slot APIs. It requires no edits to DSH source or built-in presets. The release verifier checks source and built runtimes against unmodified host commit 4d214f38c9fe03aefdfb9d900219f64f4ca85183, including the packaged browser client, administrator permissions, model catalog, account isolation, and uninstall/reinstall. See the 0.2.2 verification report. Peer dependency minimums are installation constraints, not a promise of compatibility with every future DSH commit.
Use the explicit version below to install this release.
Install or upgrade
Install version 0.2.2 from npm into your Web profile:
dsh plugin --profile web add dsh-skill-preferences@0.2.2
Restart DSH Web and refresh the browser. The package's bundle mounts the host plugin and exposes its browser module automatically. Mount it once; no dsh-skill-preferences/preset entry is needed.
To install a locally built archive instead:
dsh plugin --profile web add /absolute/path/dsh-skill-preferences-0.2.2.tgz
For a manually managed profile, install the package into $DSH_HOME/profiles/<profile>/ with the profile's package manager, then add the following to that profile's cordis.patch.yml instead of using the bundle installation above:
- insert:
- id: skill-preferences
name: 'dsh-skill-preferences'
Do not keep both manual and bundle mount entries. Existing preferences survive upgrades and uninstall/reinstall unless their saved settings are removed separately.
Use the three layers
Open Settings → Skills, choose a layer, then search for a skill and change its switch.
| Selected layer | Switch changes | Applies to |
|---|
| Global | The global disabled list | Every account and workspace |
| This user | The signed-in account's disabled list | That account across workspaces |
| This workspace | The current project root's disabled list | Every account working in that project |
Each switch shows only the selected layer's setting. The separate “Current session” status and layer labels show the combined result for the current account and workspace. Disabling a skill in a workspace leaves its global and user switches enabled unless those layers also contain a restriction.
Restrictions combine as a union: global → user → workspace. Enabling a skill clears only the selected layer's restriction; a lower layer cannot override an upper restriction. Restricted rows remain visible and explain which layer to change. An inherited restriction prevents adding a redundant lower restriction through the UI; an existing lower restriction can still be cleared.
The user layer requires an authenticated account in multiuser mode. The workspace layer requires an active session with a working directory. The plugin uses the nearest .git, .dsh, or .agents project root, or the working directory itself if no marker exists.
Saved settings and global-write access
Preferences live in DSH's persistent skill-preferences settings namespace:
skill-preferences:
disabled: [pdf]
hints: {}
byUser:
'<account-userId>':
disabled: [cad]
hints: {}
byWorkspace:
'/absolute/project/root':
disabled: [imagegen]
hints: {}
hints preserve descriptions and sources captured when skills are disabled; they do not control enforcement. User keys are account user IDs, not login names. The authenticated server determines the user; clients cannot choose another account. Workspace preferences are shared by accounts using the same normalized root, not stored per user.
In multiuser mode, only an account with the host's admin role can see the global selector and modify global preferences. Regular users' direct global-write requests are also rejected. The deprecated adminUsers field is accepted for saved-settings compatibility but no longer grants permissions. Anonymous local mode retains global access; when an authenticated account is present, its host role is respected. Workspace writes remain available to regular users.
Regular users can still see the “Globally disabled” status badge on a skill. This explains an inherited restriction and does not grant access to the global editor.
Writes are serialized, persist before reporting success, and preserve other layers. Saving invalidates the plugin's skill catalogs without restarting DSH.
HTTP integration
The plugin owns two JSON endpoints and uses the host's authentication service. Multiuser requests require a valid Authorization: Bearer <token> header. The browser reads its current DSH token for each request.
| POST endpoint | JSON body |
|---|
/plugin-skill-preferences/list | { "query": {} } |
/plugin-skill-preferences/setEnabled | { "change": { "name": "pdf", "enabled": false, "target": "workspace", "cwd": "/project" } } |
Both query and change accept optional cwd and presetId strings. The default preset is used when presetId is omitted. target is global, user, or workspace and defaults to global; workspace writes require cwd.
Success is { "ok": true, "value": { "skills": [], "userAvailable": true, "isAdmin": true } }. Each skill includes disabled, disabledLayers, modelInvocable, and userInvocable alongside its name, description, source, and provider. disabled is the combined state; use membership in disabledLayers for an individual layer. isAdmin reports the plugin's global-write permission. Errors use { "ok": false, "error": { "code": "...", "message": "..." } } and an appropriate HTTP status.
Requests are size-bounded and schema-validated. Loopback and the bound server IP are trusted by default. A named reverse proxy requires its exact host[:port] in the plugin composition option http.trustedHosts; browser origins must match that authority. These deployment options are separate from saved preferences.
Enforcement and limits
The plugin registers complete skill providers that suppress disabled skills through their model/user invocation policies. Live Agents receive providers tied to the durable session owner, keeping user-specific catalogs separate without changing shared host caches. Preference changes update model-visible catalogs on the next Agent step and affect subsequent skill loads.
- DSH's existing
/ suggestion menu may retain an older list after a save. Refresh the page to reload suggestions; the settings page includes a refresh notice.
- Before a session has a live Agent, native DSH
skill.list may read the shared preset catalog without that account's Agent provider. It can therefore omit user-layer suppression at that point. The plugin's settings API applies all three layers, and execution uses the live Agent's policy.
- Mount the plugin exactly once in the host profile. Mounting it in every preset duplicates its settings namespace.
- DSH may log its normal duplicate-skill shadowing notice for suppressed entries. Descriptions retained in
hints can become stale.
Development and verification
Install development dependencies with npm install. Tests and installation verification require a built DSH checkout and its host packages. A development lockfile containing links to that checkout is kept local.
npm test
npm run build
npm pack
npm run verify:installation -- --dsh-root /path/to/deepsleep --require-clean-host --output artifacts/installation-verification.json
prepack rebuilds both host and browser artifacts, preventing stale bundles from being packaged together. The verifier installs the archive into isolated profiles and runs real source and built CLIs. It checks the served browser bundle against its server response, account isolation, layer overlap, complete snapshots, actual model requests, persistence, and uninstall/reinstall. It uses temporary accounts and directories, without editing the normal profile.
Use --mode source or --mode built for one runtime, --keep-temp to retain diagnostic files, or --update-snapshot for an intentional reviewed output change. The snapshot and 0.2.2 report omit tokens, passwords, account IDs, and temporary paths.