DSH Plugins Marketplace

DSH Plugins

Plugins

/

Development & Infrastructure

/

dsh-skills

y

dsh-skills

Identified★ 2

Skills panel for the DeepSeek Harness left navigation: list, preview, enable/disable, install and safely uninstall Agent Skills.


description: "Skills manager for the DSH Web UI: a Skills panel in the left navigation that lists every installed Agent Skill, previews its instructions, enables or disables it, installs one from a folder, and restores what was uninstalled." kind: "plugin-readme"

dsh-skills

English | 中文

DSH Skills

A 技能 / Skills row in the DeepSeek Harness left navigation, and the page it opens.

Install · Download v0.1.0 · Landing page (github.io is unreachable on some networks — see below)

DSH discovers Agent Skills from .dsh/skills and .agents/skills — under your home and under a project — but ships no surface for seeing what is installed or for turning one off without editing files. This plugin adds that surface.

What the panel does

See everythingEvery root DSH scans, with each skill's name, description, instruction path and invocation policy.
PreviewThe full SKILL.md, frontmatter and body, without leaving the app.
Enable / disableA switch per skill. Disabled skills keep their bytes and stay on disk.
InstallCopy a folder that has SKILL.md at its top level into the root you pick. The original is never moved.
Import from GitHubPaste a GitHub repository, tree, or skill link. One repository can contribute several skills in one batch; conflicts and oversized bundles reject the whole batch without overwriting.
New skillWrite a bundle with a valid frontmatter block from a form.
Uninstall safelyUninstall moves the entry to a root-local .trash; restore it later, or delete it for good.
LocateReveal a skill or a root in Finder / Explorer / the desktop file manager.
Known librariesCodex, Claude Code, WorkBuddy and CodeBuddy keep their skills in well-known places; those that exist are listed automatically, each with that agent's mark.
Add a directoryPoint the panel at another agent's skill library — ~/.claude/skills, a colleague's checkout, a shared bundle. Its skills are listed, and DSH loads them too. The directory itself stays read-only.

Install

From GitHub. This repository is a ready-to-install package: package.json sits at the root and there is no build step, so any npm-compatible git spec resolves. In the plugin manager (Settings → Plugins), install:

github:yixin2021/dsh-skills

The same spec works from the CLI — dsh plugin forwards its arguments to pnpm inside the profile:

dsh plugin --profile desktop add github:yixin2021/dsh-skills
dsh plugin --profile desktop remove dsh-skills

https://github.com/yixin2021/dsh-skills and git+ssh://git@github.com/yixin2021/dsh-skills.git are equivalent.

From a local checkout.

dsh plugin --profile desktop add /absolute/path/to/dsh-skills

The bundle patch inserts one Loader row named skills; the client half mounts the navigation row and the panel. Reload the window after installing.

How it works

Host half (index.js) registers one authenticated JSON route, POST /api/dsh-skills, on ctx.connection.fetch. It answers list, read, set-disabled, trash, restore, purge, empty-trash, create, import-directory, import-files, install-from-remote, reveal, add-root and remove-root. ctx.skills.registerProvider publishes the discovered libraries and the added directories to the model. lib/skills-core.js owns the skill grammar — frontmatter parsing, root discovery, entry scanning — so the route and the tests agree on what a skill is.

Client half (client.js) registers a sidebar.panellist icon under the id dsh-skills and the main panel keyed by that same id, which is how the layout addresses a panel. It never reads a skill root itself: every fact arrives through the route, so the browser has no filesystem authority.

Importing from GitHub

A skill that lives in a GitHub repository is one directory bundle: <dir>/SKILL.md plus whatever it references. Paste a GitHub link and the panel reads the archive, shows the skills it finds, and lets you select one or several for a single import. The Host validates every selected bundle before writing any of them: an existing name, an invalid path, or a size/file-count limit rejects the whole batch without overwriting or leaving a partial install.

LinkHow it is read
https://github.com/owner/repoThe archive service — one request, no rate limit.
https://github.com/owner/repo/tree/main/skills/fooThe same, narrowed to that directory.
https://gitlab.com/owner/repo/-/tree/main/skills/fooCloned, then narrowed.
https://gitee.com/owner/repo/tree/main/skills/fooCloned, then narrowed.
git@host:owner/repo.gitCloned over SSH.
https://host/owner/repo.git#branchCloned at that branch.

GitHub has an archive endpoint that answers with the whole tree in one request and no rate limit, so it is read that way; every other git host is cloned, shallowly, into a temporary directory that is deleted as soon as the tree has been read. Both paths end in the same tree, and lib/skill-tree.js owns the policy both obey: which directory holds a SKILL.md, which files belong to it, and which paths may become a file name.

A repository that holds several skills is a catalogue. The dialog shows checkboxes, starts with all visible candidates selected, and supports selecting or clearing all. If more than 40 candidates are found, the dialog reports the total and suggests narrowing the GitHub link to a subdirectory. A branch whose name contains a slash (release/2.0) is resolved by trying the possible branch/path splits until the requested directory is found.

A private repository needs an access token. The dialog has a field for one, and it is optional: a public repository never carries a token, so none is sent. The token is used for that one download and is never written to disk. For a git clone it travels in the child's environment rather than in the command line, where every process on the machine could read it.

The transport is restricted. git understands transports beyond HTTP and SSH, and some of them run commands — ext:: executes a shell command, and file:// reads the machine's own disk. A pasted link must never reach either, so the URL is checked against an allowlist (https, http, ssh, git) before git sees it, a local path is refused as "not a remote repository", and GIT_ALLOW_PROTOCOL narrows it again inside the child process. The clone is also told not to prompt: a credential prompt in a background panel is a hang nobody can answer.

Nothing inside a repository is executed. The archive is unpacked in memory, the clone is read as files, symlinks are skipped rather than followed, and every path is resegmented before it becomes a file name.

Disabling without deleting

DSH only discovers direct children of a skill root. A disabled skill is moved to <root>/.disabled/<name> — hidden, therefore invisible to every provider — and moved back untouched when re-enabled. Nothing in SKILL.md is rewritten, so a hand-written skill survives a round trip byte for byte. The same trick backs .trash.

Known agent libraries

Five libraries are found on their own, so a machine that already runs another coding agent needs no configuration. This is the order the page lists them in:

MarkLibraryPath
DeepSeekDeepSeek Harness$DSH_HOME/skills (usually ~/.dsh/skills)
DeepSeekAgents$DSH_AGENTS_HOME/skills (usually ~/.agents/skills)
CodexCodex$CODEX_HOME/skills (usually ~/.codex/skills)
Claude CodeClaude Code$CLAUDE_CONFIG_DIR/skills (usually ~/.claude/skills)
WorkBuddyWorkBuddy$WORKBUDDY_HOME/skills (usually ~/.workbuddy/skills)
CodeBuddyCodeBuddy$CODEBUDDY_HOME/skills (usually ~/.codebuddy/skills)

Discovery runs on every read rather than being remembered, so installing another agent later just works, and deleting a library removes it from the list. These libraries are read-only for the same reason added directories are: DSH does not own those bytes.

The marks are the vendors' own, taken from published brand assets rather than drawn here: the DeepSeek whale (deepseek.svg from simple-icons), the OpenAI knot and the Claude asterisk (openai.svg, claude.svg from @lobehub/icons-static-svg), and the official logo.svg tiles served by codebuddy.ai and workbuddy.cn. The monochrome ones inherit currentColor so they follow the theme; the two tiles keep their own gradients. Brand marks belong to their owners and identify the directory the skills came from.

Added directories

DSH scans four roots and no others, so the plugin registers its own skill provider (ctx.skills.registerProvider) that serves the added directories with source: 'custom' — the label DSH reserves for exactly this. The model sees those skills in its catalog, with the invocation policy from each frontmatter, and a symlinked bundle counts as a skill (Claude Code and stow both link rather than copy). Adding or removing a directory invalidates the catalog, so the next model step sees the change without a restart.

The directories themselves stay read-only in the panel: no enable/disable, no uninstall, no create, and never an install target. DSH does not own those bytes, and a switch there would edit another tool's library. "Install…" copies a skill into a root DSH does own. The Host refuses mutations with code: 'read-only', so the rule does not depend on the page behaving.

The list lives in $DSH_HOME/skills-roots.json — beside the skills rather than inside a profile, so it survives a profile rebuild and is shared by the web and desktop apps. A malformed file is read as an empty list; adding a directory rewrites it. Keys are hashed from the path, so removing one directory never re-points another's filter.

Scoping

All writes go through resolveWithin, which refuses a path that leaves its root. Skill names match ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$; a requested entry must already exist where the request claims it does; a create or install refuses to overwrite an existing enabled, disabled or trashed entry. A remote import obeys the same rules: its paths are resegmented before they become file names, and a symlink inside a repository is skipped rather than followed.

UI conventions

  • Only Host theme tokens (--dsw-alias-*) are used — no hard-coded palette, so light and dark themes both work.
  • Every visible string goes through ctx.locale.register / ctx.locale.bind with a zh and an en dictionary; the row's label is a locale-aware function, not a captured string.
  • React here is the shell's curated object, which exposes only createElement, useState and useEffect. The panel uses exactly those three: anything else — useSyncExternalStore, useRef, memo — is undefined and throws at render, which blanks the panel.
  • No Harness Client package is imported. Every control is a plain element styled from tokens, so the panel cannot break on a missing primitive module or an invented prop name.
  • Dialogs are announced as role="dialog" / aria-modal, close on Escape and on a backdrop click, and the enable/disable control is a real checkbox with an accessible name.
  • No DOM outside the panel is touched, and nothing is appended to document.body except the transient folder-picker input, which is removed as soon as the picker closes.

Tests

npm test

Runs node --check on all seven sources, then 90 tests over a real temporary tree and over fixtures built in the test itself: frontmatter parsing (quoted scalars, comments, block scalars, invalid flag spellings), path containment, root discovery, direct-children-only scanning, and every mutation including the refusals — plus the remote path: link parsing, the transport allowlist, the tar reader, and the clone.

Known limits

  • Binaries are not carried by import-files, since the route transports text; use import-directory or copy assets into the bundle afterwards.
  • A skill stored outside the four roots DSH scans is not listed, because DSH would not load it either.
  • The panel shows what a root holds now; it does not watch the filesystem, so use the reload control after editing files on disk.
  • A remote import needs either git on the machine (for every host but GitHub) or a link to a GitHub repository.
  • A repository is read whole; a very large one costs one download or one shallow clone, and archives beyond 24 MB are refused rather than downloaded.

Comments

Loading…

From the same category

awesome-dsh-plugin

by awesome-dsh-plugin

A curated list of plugins for DeepSeek Harness (dsh) · DeepSeek Harness 插件精选列表

Development & Infrastructure

★ 22.2k

CC0-1.0

Python

Nov 3, 2026

Index only — not installable

by 0xsline

DeepSeek Harness (DSH) ecosystem: curated plugins, tools, and infrastructure from dsh-external/hub and the public dsh-plugin topic.

Development & Infrastructure

★ 1.3k

CC0-1.0

Python

Oct 16, 2026

Index only — not installable

by Yuuyuko-uu

DSH 鱼的记忆:给会话一份会淡忘的长期记忆,每条都带时间

Development & InfrastructureMemory & ContextSessions & MessagesManifest valid

★ 464

MIT

JavaScript

Nov 3, 2026

dsh plugin --profile web add dsh-fish-memory

by uumit-ai

Open dsh web from your phone or another computer through a UUMit account, without running your own server or installing another program: a built-in tunnel client connects to UUMit's hosted tunnel, and

Tools & CapabilitiesDevelopment & InfrastructureTerminal & ClientsManifest valid

★ 454

↓ 268/wk

MIT

JavaScript

Oct 21, 2026

dsh plugin --profile web add @uumit-ai/dsh-uumit-remote

by SAOS-3624

Scene-aware storyboard for DeepSeek Harness: 9-16 numbered cells with timestamps + transcript + an audio envelope, packed into ONE image (384 tokens). Two tools: video_storyboard and video_zoom.

Tools & CapabilitiesVision & MultimodalDevelopment & InfrastructureManifest valid

★ 419

↓ 17k/wk

MIT

JavaScript

Nov 3, 2026

dsh plugin --profile web add dsh-video-storyboard

by xiajiajun516

DeepSeek Harness (DSH) backup & restore plugin — export, import, migrate and sync your complete DSH configuration, plugins, MCP servers, skills and workspace. One-click migration to another machine.

Development & InfrastructureManifest valid

★ 292

↓ 8.8k/wk

MIT

TypeScript

Nov 2, 2026

dsh plugin --profile web add dsh-config-manager