@royenheart/dsh-plugin-skills-manager

August 31, 2026 · View on GitHub

dsh

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.



Global skill settings

Session skill settings

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:

GapPatch
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 togglepatches/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 generic sidebar.workspaces.entry list 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' } to API_REMOTE_FORWARDED_EVENTS and has ui-skill clear every session catalog cache.

Dropped versus earlier releases (do not apply the old files):

  • deny-wins / skill.list source+cwd (old 0002) — the plugin registers enforcement on each preset standing layer (same layer as skill-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 as scope (scope.id is 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

  1. Global skill settings — settings page; overrides go to the skills-manager namespace in settings.yaml.
  2. Workspace overrides — overflow "Manage skills" (patch 0001) and the settings workspace tab. Discovery uses host ctx.skills.list({ cwd }) via the plugin HTTP route.
  3. Session overrides — conversation "Skills" tab; Shift range-select / Ctrl toggle, then batch enable/disable.

Managed sources

Only .agents and dsh skill roots:

sourcepathmeaning
project-dsh<project>/.dsh/skillsdsh project dir
project-agents<project>/.agents/skillsshared .agents
user-dsh$DSH_HOME/skillsdsh user dir
user-agents~/.agents/skillsuser .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:

  1. agentPresets.list() / standingKeyFor(id) for every mountable preset
  2. createScope(ctx, key) using that same key object
  3. registerProvider on 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

ProbeWhen the seam is missingNotice
sidebar.workspaces.entry undeclaredslots.inject never fires; settings workspace tab remainsSilent
Settings namespace unavailablePanel is read-onlyToast + banner
List rows have no sourceNo .agents/dsh filter; every discovered name is shownToast + banner
Plugin HTTP and { cwd } list both failWorkspace tab falls back to a same-cwd session, then manual namesToast + banner
Standing enforcement did not winPanel still stores overrides; banner warns the model may still see the skillToast + banner

Tests

npm test            # node --test tests/*.test.ts
npm run build       # tsdown host + client