DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-catalog

d

dsh-catalog

Manifest valid

Unify the scanning, merging, and visualization of all skills that DSH can read, solving the pain point of "too many skills and no idea which command belongs to which source."

UI (client)hasBundlePatch

dsh-skill-catalog

A DeepSeek Harness (DSH) plugin (not a skill): scan every skill your DSH can load, merge them into one browsable catalog, and put it in a sidebar panel — solving "too many skills, no idea which command comes from which source". DSH natively supports / invocation, so this plugin only does cataloging and browsing — it registers no slash commands of its own.

English | 中文

Features

  • Single entry point: a button at the bottom of the DSH left sidebar (next to Settings) opens a narrow panel on the right that sits beside the conversation instead of covering it.
  • Scans exactly what DSH can load: every direct child of ~/.dsh/skills and ~/.agents/skills becomes a collection (single-skill directory, skills/ skill pack, or loose .md). Inclusion rules mirror DSH's own source and skill-pack provider loading rules — if DSH won't load it, it is not listed.
  • Refresh: the ↻ button re-scans SKILL.md from disk.
  • Click to insert: clicking a command card writes /command straight into the current conversation input (via DSH's uiSession.current.value.props.inputActions, preferring setDraft(text)); falls back to copying to the clipboard when the composer is unavailable.
  • Right-click for details: right-click a command card for an info card explaining what it does (your custom note takes precedence — see below). The card flips away from viewport edges; it closes on left-click elsewhere, Esc, list scroll, the ✕ button, or right-clicking the same card again.
  • Native tool dsh_catalog: ask in chat "what is /estimate" or "which skills do I have" and get the three-level catalog (collection › category › command) plus the panel address.
  • Custom categories (saved, persistent): paste "category + commands" in the panel's ⚙ Categories editor — saved once, effective forever. See Custom categories.
  • Custom command notes (saved, persistent): paste a Markdown table in the panel's ✎ Notes editor; right-clicking a command then shows your note (the skill's own description is kept as an "original description" footnote), and noted commands carry a blue marker and a "noted" badge. See Custom command notes.

Scan sources

SourceSkill location (scan roots)Parser
DeepSeek Harness~/.dsh/skills, ~/.agents/skills (each direct child = one collection)skill_md

Three-level structure: collection › category › command. Core rules (mirroring "how DSH reads skills"):

  • Collection = the file name one level below a skills root. DSH reads skills from ~/.dsh/skills and ~/.agents/skills (project-level <project>/.dsh/skills and <project>/.agents/skills exist too; this plugin does not scan those yet). Each direct child is a collection:
    • <root>/<name>/SKILL.md — single-skill collection
    • <root>/<name>/skills/<s>/SKILL.md — skill-pack collection, one command per skill inside the pack
    • <root>/<name>.md — loose skill collection (name = file stem)
    • pure resource directories (neither layout) are skipped entirely
  • Category has three sources, highest priority first:
    1. Custom categories saved in the panel (see below)
    2. the skill frontmatter's category
    3. Auto-categorization — keyword extraction from name + description (weighted, stop-worded), grouped by "same primary topic". Zero config, zero rule tables. The category dropdown is linked to the collection: pick a collection first, then its categories appear.
  • Command = the skill name (/name). Inclusion rules mirror DSH's source (isPotentialSkillPath, max 2 path segments below the root) plus the skill-pack provider's loading rules.

Custom categories

Auto-categorization is the zero-config fallback, but if you have your own taxonomy for a skill library (e.g. 74 commands split into Onboarding / Game Design / QA & Testing), paste it once in the panel and it sticks.

How to

  1. Click ⚙ Categories at the top right of the panel;
  2. pick the collection the rules belong to (defaults to the current filter; "All collections" matches by command name across collections);
  3. paste lines of the form category name followed by its commands:
Onboarding & Navigation /start /help /project-stage-detect /adopt /settings
Game Design /brainstorm /map-systems /design-system /quick-design
QA & Testing /qa-plan /smoke-check /soak-test /regression-suite
  1. Click Save & apply. The panel reports how many categories/commands were parsed and how many matched the current catalog.

Parsing is lenient: tokens starting with / are commands, everything else merges into the category name (so names with spaces and & like Onboarding & Navigation work as-is); leading -, 1., # and backticks are stripped; commands dedupe within a category; order is preserved — what you paste is what the editor shows when you reopen it.

Why refresh / plugin installs & removals never lose it

ScenarioMechanism
Click ↻ RefreshRefresh only re-scans SKILL.md; every catalog build re-reads and re-applies your rules
Reopen the client / restart DSHRules live on disk, independent of any process
Uninstall/update this pluginRules live in ~/.dsh-catalog/, not in the plugin directory and not in the assets/ runtime artifact
Another plugin is removedRules are stored by command name and only match, never filter: a missing command keeps its rule and recovers automatically when the plugin returns
Install a new pluginCommands not in any rule go to (Uncategorized) in strict mode, otherwise auto-categorization

Storage location and format

~/.dsh-catalog/categories.json (created on first save):

{
  "version": 1,
  "updated_at": "2026-01-01T00:00:00",
  "rules": [
    {
      "collection": "my-game-skills",
      "category": "Game Design",
      "commands": ["brainstorm", "map-systems", "design-system"]
    }
  ],
  "strict_collections": ["my-game-skills"]
}
  • collection empty = global rule (matches by command name, any collection).
  • strict_collections: commands in these collections that no rule lists all go to (Uncategorized), dropping auto-categorization (the checkbox in the editor). Uncheck to let new skills keep auto-categorizing.
  • If the file is corrupted it is backed up as *.corrupt-<timestamp>.json and scanning continues with empty rules.

HTTP API

The panel talks to these endpoints (the server listens on 127.0.0.1 only):

MethodPathDescription
GET/api/custom?collection=XRead saved rules; also returns an editable paste-format text
POST/api/customSave. body: { text | rules, collection, strict, mode }, mode = replace (default) or merge
POST/api/custom/resetClear all custom categories

Custom command notes

A skill's own description is often one English sentence that doesn't tell you how to use it. This feature lets you write your own note, shown on right-click.

How to

  1. Click ✎ Notes at the top right of the panel;
  2. pick a collection and paste a table like this (the most common shape of a skill list — copy it straight in):
| Command | Note |
|---|---|
| **ask-matt** | Skill router. Ask it when unsure which skill/flow to use. |
| **code-review** | Dual-axis code review: repo standards + requirement spec, parallel subagents, side-by-side report. |
  1. Click Save & apply; right-clicking a command card now shows your note.

Parsing: split on |, the first cell is the command name (**, backticks and a leading / are stripped), the rest merges into the note; header rows (| Command | Note |) and |---|---| separator rows are skipped automatically; name: note and name␣␣note (two or more spaces) also work. Order is preserved and round-trips into the same table format.

Display rules

CaseRight-click info card shows
Custom note existsYour note (body); the skill's description as an "original description" footnote
No custom noteThe skill's own description (as before)

The info card is position: fixed, follows the cursor, and flips back inside the viewport near edges; long notes scroll inside the card. Right-click the same card again to close (toggle); right-clicking a different card switches content. Other ways to close: left-click elsewhere, Esc, scroll the list, or the ✕ on the card.

Noted commands carry a blue left marker and a "noted" badge, and the search box matches note text too.

Persistence

Same mechanism as custom categories: stored in ~/.dsh-catalog/notes.json (not in the plugin directory, not in assets/), re-read on every catalog build — refresh, reopen, reinstall, and other plugins' installs or removals don't affect it. Notes are stored by command name and kept while a command is missing.

{
  "version": 1,
  "updated_at": "2026-01-01T00:00:00",
  "notes": [
    { "collection": "dsh-mattpocock-skills", "command": "ask-matt", "note": "Skill router…" }
  ]
}

collection empty = global (matches by command name, any collection).

HTTP API

MethodPathDescription
GET/api/notes?collection=XRead saved notes; also returns an editable table text
POST/api/notesSave. body: { text | notes, collection, mode }
POST/api/notes/resetClear all custom notes

Install (DSH plugin)

# From npm (once published):
dsh plugin --profile web      add dsh-skill-catalog
dsh plugin --profile desktop  add dsh-skill-catalog

# Or from a local checkout (any profile; web = dsh web, desktop = DSH desktop client):
dsh plugin --profile web      add "link:/absolute/path/to/dsh-skill-catalog"
dsh plugin --profile desktop  add "link:/absolute/path/to/dsh-skill-catalog"

# Verify registration
dsh web --dump-config | findstr dsh-skill-catalog
dsh web                      # restart the harness

Uninstall: dsh plugin --profile web remove dsh-skill-catalog

The panel UI needs the right-sidebar services (@deepseek-ai/dsh-client-ui-sidebar-right). Profiles without them still get the tool and the HTTP service — only the panel stays hidden.

Configuration

Env varDefaultDescription
DSH_CATALOG_PORT8765Preferred port for the panel server (falls back 8765→8769 on conflict). The sidebar panel auto-discovers ports in the 8765–8769 range only; moving the server outside that range (e.g. 9000) breaks panel discovery, though the API stays reachable at that port directly

Custom data locations are documented under Custom categories (~/.dsh-catalog/categories.json, edited in the panel, not by hand).

Including skill libraries from elsewhere

Scan roots are fixed to DSH's own two skills roots: ~/.dsh/skills and ~/.agents/skills. To bring a library from elsewhere (e.g. D:\path\to\skills) into the catalog, link it in — no code changes needed:

# Recommended shape: real parent directory, skills inside points at the target
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills\MyLib"
New-Item -ItemType Junction -Path "$env:USERPROFILE\.agents\skills\MyLib\skills" `
                            -Target "D:\path\to\skills"

All three link shapes are recognized (the scanner detects the layout, so a link can no longer make a whole entry vanish):

ShapeStructureResult
Skill pack<name>/skills/<s>/SKILL.mdone command per skill in the pack
Folded link<name>/<s>/SKILL.md (link points directly at skills/)same, validated by directory name
Single skill<name>/SKILL.mdone command

Using it in DSH

  • Sidebar: click the book icon at the bottom of the DSH left sidebar to open the visual catalog.
  • Chat: call dsh_catalog (accepts query / collection / refresh).
  • Click-to-insert: clicking a command card writes /command into the current conversation input (or copies it); press Enter to invoke.

Privacy

  • The panel server listens on 127.0.0.1 loopback only, never exposed.
  • The scan artifact assets/command-catalog.json contains local absolute paths; it is a runtime artifact and excluded via .gitignore. The repository contains no hardcoded local paths or personal data.
  • Personalization lives outside the repository: custom categories in ~/.dsh-catalog/categories.json (local collection and command names, not distributed with the repo).
  • Auto-categorization is driven entirely by each skill's own name/description; nothing is uploaded and no external service is contacted.

Structure

dsh-catalog/
  package.json          Plugin manifest (dsh.bundle.patch / dsh.client)
  cordis.patch.yml      Plugin registration (bundle insert)
  lib/index.js          Cordis host entry: registers the tool + starts the panel server
  lib/scan.js           DSH skill scanner (no third-party deps, Node port):
                        direct children of skills roots = collections
                        (single skill / skill pack / loose), auto-categorization
                        + custom category application
  lib/customCategories.js  Custom categories: persistence
                        (~/.dsh-catalog/categories.json), paste parsing,
                        override application
  lib/customNotes.js    Custom command notes: persistence
                        (~/.dsh-catalog/notes.json), table parsing,
                        right-click info card display
  lib/store.js          User-data directory + legacy-location migration
  lib/server.js         Panel data HTTP service (/api/catalog, /api/refresh,
                        /api/mode, /api/custom R/W, /api/custom/reset,
                        /api/notes R/W, /api/notes/reset)
  client.js             DSH browser entry: registers via window.__ModuleLoader__.load
                        sidebar icon (sidebar.footer.action) + right panel
                        (sidebarRight), native React components, data via
                        /api/catalog
  assets/icon.svg       Plugin/sidebar icon
  assets/command-catalog.json  Scan artifact (runtime-generated, gitignored)

Extending: add a scan source

Append one record to the SOURCES list in lib/scan.js; no parsing logic changes needed. collection is usually omitted — collection names are derived from the directories the roots actually hit:

{
  client: "My Source",
  kind: "skill_md",            // DSH skills-root source
  roots: ["~/.mysource/skills"],
  // collection: "explicit name", // only for non-directory sources
}

License

MIT

Comments

Loading…