DeepSeek Harness plugin

dsh-skill-panel-nianchen

Skill management panel for the DeepSeek Harness web app.

Jump to install

Source facts

Repository
nianchen8/dsh-skill-panel
Latest update
Aug 20, 2026
Category
Plugin Markets & Managers
GitHub stars
2
Format
bundle
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/nianchen8/dsh-skill-panel
Plugin: dsh-skill-panel-nianchen
Author: nianchen8

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.mdSource · read only

dsh-skill-panel

A skill management panel for the DeepSeek Harness web app: browse, search, filter, enable/disable, and uninstall your agent skills from the settings page or the sidebar.

Built entirely on the harness's public plugin surface — a Typert Remote service on the host half, slot-registered React UI on the browser half. No forks, no internal APIs, no build step (pure JS); runtime imports are limited to the harness-provided @deepseek-ai/dsh-storage-domain and zod (declared as dependencies).

Features

  • Skill list with name, description, source label, and per-source counts
  • Search and source filtering (user .agents, user .dsh, project roots, custom, bundled)
  • Model / User invocation switches (rewrites the SKILL.md frontmatter; unspecified switches are preserved)
  • Disable / Enable button — fully disables a skill while remembering its previous state, and restores exactly that state on enable
  • Uninstall with two-step confirm (deletes the skill directory, bundled skills are protected)
  • Detail view with whenToUse, on-disk path, and the SKILL.md body
  • Skill groups — create / rename / delete groups, manage membership per group (add / remove skills), browse skills grouped; persisted through the official ctx.storageDomain (no self-made storage files)
  • All reads are session-scoped — the panel shows exactly the catalog your current session serves
  • Writes invalidate discovery synchronously, and the slash-menu cache is refreshed through the official forwarded events

Requirements

  • DeepSeek Harness 0.1.0-rc.6+ (web profile)
  • pnpm available (corepack enable provides it)

Install

corepack enable                                   # once per machine
dsh plugin --profile web add dsh-skill-panel     # from npm
# or: dsh plugin --profile web add github:nianchen8/dsh-skill-panel
dsh web                                           # restart to load the package

The panel then appears under Settings → Skills and the sidebar's Skills button.

How it works

SKILL.md files (project / user / bundled roots)
        │  discovery (skill-filesystem providers, layered per scope)
        ▼
host skill registry  ── snapshot({cwd, scope: agent}) ──► SkillPanelService (Typert Remote)
        ▲                                                       │  /api/skillPanel/*
        │  fs/observed invalidation                             ▼
        └── frontmatter writes / deletions               browser client (fetch RPC)
                                                                 │  slots.register
                                                                 ▼
                                              Settings page · sidebar button · overlay
  • Host half (index.js): a TypertRemoteService with twelve Remote endpoints — getConfig, listDetailed, getDetail, setInvocation, setDisabled, uninstall, plus the group CRUD groupList, groupCreate, groupUpdate, groupDelete, groupAddSkill, groupRemoveSkill. Reads resolve the session-scoped skill view (same catalog the model sees); writes rewrite SKILL.md frontmatter or delete the skill directory, then emit fs/observed for synchronous discovery invalidation and replay agent-preset/selected so the official slash menu drops its cached catalog. Groups live in a ctx.storageDomain domain (skill_groups), opened lazily and closed on unload; when storage is unavailable the panel degrades to a read-only group view.
  • Browser half (client.js): plain React via the platform module table, registered into sidebar.footer.action, shell.overlay, and settings.section. All data crosses the standard API gateway over /api/skillPanel/<method>.

Placement configuration

The three UI entries (sidebar button, overlay, settings page) default to the tail of their slot: at registration the browser half reads the slot's live entries and places itself after the largest existing order, so a fresh deployment always lands at the bottom of the list regardless of how many entries already occupy the slot.

Arrival semantics (why same-strategy plugins don't fight): the tail order is computed once at registration — the browser half never re-registers after it arrives. Each registration is an atomic read→compute→register, so the next arrival always sees the previous one and appends strictly after it (max + 1, no ties). Once an entry lands, its position is fixed; if it later unloads and comes back (fiber restart), it re-appends at the tail again. Two plugins using this identical strategy therefore coexist as A(0), B(1), C(2), … with the latest arrival always last — no chasing, no livelock.

Each entry can be individually overridden through the loader entry's config in the profile composition (profiles/<name>/cordis.patch.yml):

- id: skill-panel
  config:
    entries:
      sidebar:
        enabled: true        # show the sidebar button (default true)
        order: 5             # explicit position; omit = dynamic tail
        # slot: conversation.session.header.actions   # optional relocation
      overlay:
        enabled: true
        order: 10
      settings:
        enabled: false       # hide the settings page
  • enabled — whether the entry registers at all.
  • order — exact ascending position in the slot; absent means dynamic tail (max existing order + 1 at registration time).
  • slot — target slot key; omit for the built-in seats above. When relocating, the component degrades gracefully to the props the new slot provides (useSessions/wide are optional in the panel code).

The resolved placement is exposed to the browser through skillPanel/getConfig; if the endpoint is unavailable (e.g. before a restart), the browser half falls back to the defaults above.

Development

The package is pure JavaScript; edit index.js / client.js, then restart dsh web (the client bundle is rescanned at boot).

node --check index.js client.js
npx oxlint --deny-warnings index.js client.js

License

MIT