Bundle
dsh-skill-preferences
Global, user, and workspace skill preferences for DeepSeek Harness
- Source
- zc679087
- License
- MIT
- Updated
- Updated 16 hours ago
Readme
# dsh-skill-preferences
Manage [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) skills in **Settings → Skills**, with global, user, and workspace preferences.
[简体中文](README.zh-CN.md)
## 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](artifacts/installation-verification-0.2.2.json). 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:
```sh
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:
```sh
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**:
```yaml
- 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:
```yaml
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.
```sh
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](tests/snapshots/installation.json) and [0.2.2 report](artifacts/installation-verification-0.2.2.json) omit tokens, passwords, account IDs, and temporary paths.
Install
dsh plugin --profile web add github:zc679087/dsh-skill-preferences
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-skill-preferences 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.