@royenheart/dsh-plugin-skills-manager
August 31, 2026 · View on GitHub
dsh plugin: enable or disable skills in session > workspace > global scopes (then default(enabled)). A disable applies to both the model skill catalog and user /skill invocation.
Required dsh patches (UX only)
Baseline: dsh 0.1.2-alpha.2 (master). Enforcement no longer needs a harness merge-rule or skill.list wire patch. Two general-purpose UI seams are still missing upstream; apply them before a full UX match:
| Gap | Patch |
|---|---|
| Workspace overflow has no per-entry list slot, so the plugin cannot add "Manage skills" | patches/0001 (Discussion #1413) |
Host skills/change is not forwarded; the / picker cache stays stale after a toggle | patches/0003 |
cd /path/to/deepseek-harness # clean 0.1.2-alpha.2 / master
git am /path/to/dsh-plugin-skills-manager/patches/0001-feat-add-sidebar-workspaces.entry.patch
git am /path/to/dsh-plugin-skills-manager/patches/0003-fix-forward-skills-change-to-web-clients.patch
pnpm install
pnpm run build
0001: declares the genericsidebar.workspaces.entrylist slot (id/label/order/icon) and projects those rows between Rename and Delete in the workspace overflow menu.0003: adds{ event: 'skills/change', mode: 'emit' }toAPI_REMOTE_FORWARDED_EVENTSand hasui-skillclear every session catalog cache.
Dropped versus earlier releases (do not apply the old files):
- deny-wins /
skill.listsource+cwd(old 0002) — the plugin registers enforcement on each preset standing layer (same layer asskill-filesystem, rank 50) and lists skills through plugin HTTP (GET /plugins/@royenheart/dsh-plugin-skills-manager/skills). - lookup
sessionId(old 0004) — a live agent lookup already uses the Agent asscope(scope.idis the session id). A blank session's/menu may still list a session-disabled name until the first step; the model catalog does not.
Settings namespaces are exposed to the Web plane on 0.1.2 by registration; no expose patch is required.
Without 0001 the settings-page workspace tab still works. Without 0003, disable still hides the skill from the model catalog; the / menu and /name chips update only after a preset switch or reconnect.
Features
- Global skill settings — settings page; overrides go to the
skills-managernamespace insettings.yaml. - Workspace overrides — overflow "Manage skills" (patch 0001) and the settings workspace tab. Discovery uses host
ctx.skills.list({ cwd })via the plugin HTTP route. - Session overrides — conversation "Skills" tab; Shift range-select / Ctrl toggle, then batch enable/disable.
Managed sources
Only .agents and dsh skill roots:
| source | path | meaning |
|---|---|---|
project-dsh | <project>/.dsh/skills | dsh project dir |
project-agents | <project>/.agents/skills | shared .agents |
user-dsh | $DSH_HOME/skills | dsh user dir |
user-agents | ~/.agents/skills | user .agents |
Other agent trees (.claude/skills, .codex/skills, …) and bundled/runtime/custom are ignored. See src/core/skill-filter.ts.
Install
The package is a dsh profile bundle. dsh plugin add reconciles dsh.profile.bundles.
cd dsh-plugin-skills-manager
python3 install.py install # build + link into the profile
python3 install.py uninstall
DSH_PROFILE (default web), DSH_HOME (default ~/.dsh).
How disable reaches the model
The three-layer store is plugin settings, not a dsh patch. On start (and when the preset roster or a standing key changes) the host:
agentPresets.list()/standingKeyFor(id)for every mountable presetcreateScope(ctx, key)using that same key objectregisterProvideron that scoped context (rank 50)
A remount mints a new key object; the plugin drops the old bind and registers again. Override rows in settings are unchanged.
The model catalog (tool-skill's <available_skills>) keeps only modelInvocable === true entries. After the standing bind wins, a disabled name is absent from that catalog — the model never sees foo.
Compatibility
| Probe | When the seam is missing | Notice |
|---|---|---|
sidebar.workspaces.entry undeclared | slots.inject never fires; settings workspace tab remains | Silent |
| Settings namespace unavailable | Panel is read-only | Toast + banner |
List rows have no source | No .agents/dsh filter; every discovered name is shown | Toast + banner |
Plugin HTTP and { cwd } list both fail | Workspace tab falls back to a same-cwd session, then manual names | Toast + banner |
| Standing enforcement did not win | Panel still stores overrides; banner warns the model may still see the skill | Toast + banner |
Tests
npm test # node --test tests/*.test.ts
npm run build # tsdown host + client