Bundle
dsh-skills-nexus
Universal DSH skill adapter — register any GitHub SKILL.md repo as a DSH skill via one command.
- Source
- xiaxi626
- stars
- 1 stars
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-skills-nexus
[](https://github.com/xiaxi626/dsh-skills-nexus/actions/workflows/ci.yml)
[](https://www.dsh.so/artifact/dsh-skills-nexus/)
[](https://www.dsh.so/artifact/dsh-skills-nexus/)

**English** | [中文](README_CN.md)
⭐ **If this project helps you, welcome to Star for support!**
A universal DSH skill adapter. **Install once**, then register **any** GitHub
repo that contains a `SKILL.md` as a DSH skill — one command at a time. The
skill repo itself stays pure: no Cordis plugin code, no `package.json`, no
`cordis.patch.yml` required.
Nexus works by cloning SKILL.md repos to a local `~/.dsh/skills-nexus/repos/`
directory and creating symlinks in the official DSH skills root
(`~/.dsh/skills/`). The official filesystem provider automatically discovers,
watches, and serves them — no custom provider or runtime scanning needed.
## Why
`dsh plugin --profile <name> add "github:owner/repo"` forwards to pnpm, and
**only packages with `dsh.bundle.patch` are activated as profile layers**. A
content repo with just `SKILL.md` + `references/` + `scripts/` has no Cordis
wrapper, so this path doesn't work. `dsh-skills-nexus` fills the gap:
| command | installs | requires `dsh.bundle.patch`? |
|---|---|---|
| `dsh plugin add github:owner/dsh-skills-nexus` | nexus itself (once) | yes |
| `dsh-skills-nexus add github:owner/any-skill` | pure SKILL.md content repo | **no** |
> **Not sure which command fits your repo?** Read
> **[nexus vs `dsh plugin` — when to use which](docs/nexus-vs-plugin.md)**.
> Short version: repo has `SKILL.md` → nexus; repo is a pure plugin
> (`cordis.patch.yml` / `dsh.bundle.patch`, no `SKILL.md`) → `dsh plugin`;
> has both → your choice (nexus = content, plugin = code).
## Install nexus
```bash
dsh plugin --profile web add "github:xiaxi626/dsh-skills-nexus"
```
Restart the profile once. The `dsh-skills-nexus` CLI command is then available.
`lib/` compiled artifacts are committed with the repo — install and use.
## Usage
```bash
# register a skill repo (cloned under ~/.dsh/skills-nexus/repos/<name>/)
dsh-skills-nexus add github:owner/repo
dsh-skills-nexus add github:owner/repo#dev # pick a branch/tag
dsh-skills-nexus add https://github.com/owner/repo
dsh-skills-nexus add owner/repo # shorthand
dsh-skills-nexus add github:owner/repo --yes # skip "wrapped repo?" prompt
dsh-skills-nexus add github:owner/repo --subdir skills/foo # install one subdir of a collection repo
dsh-skills-nexus add github:owner/repo --subdir skills --name owner-skills # custom entry name (fallback chain: --name > subdir leaf > repo name)
# inspect / maintain
dsh-skills-nexus list # all registered skills (+ commit, subdir, status)
dsh-skills-nexus update [name] # refresh (branch pin: pull; tag/commit pin: verify)
dsh-skills-nexus enable <name> # create symlink (default)
dsh-skills-nexus disable <name> # remove symlink without deleting clone
dsh-skills-nexus remove <name> # delete clone + symlink + unregister
```
Value options (`--name`, `--ref`, `--subdir`) also accept the `--flag=value` form (e.g. `--subdir=skills/foo`, `--name=owner-skills`); the boolean `--yes` takes no value.
Accepted repo forms: `github:owner/repo[#ref]`, full `https://` URL (incl.
`/tree/<ref>/...` subpaths), `git+https://`, `git@`/`ssh://`, and bare
`owner/repo` shorthand.
When you `add` a repo, nexus inspects the clone before registering it:
- **Plain SKILL.md repo** — registered directly.
- **SKILL.md + DSH plugin wrapper** — asks whether to ignore the wrapper and manage as a plain SKILL.md repo. Type `y` to continue, `n` to abort and suggest installing via `dsh plugin add`. Use `--yes` to skip the prompt.
- **Pure DSH plugin (no SKILL.md)** — prints a message telling you to use that repo's own DSH plugin installation flow, then exits without registering.
- **Neither** — reports that no SKILL.md or DSH plugin marker was found and exits with an error.
- **Collection repos** (`skills/<name>/SKILL.md` layout, e.g. `trae-community/trae-skills`) — installing the whole repo yields no installable skill at the root; nexus rejects it and suggests `--subdir <path>`. Installations that yield more than 20 skills trigger a confirmation prompt (skip with `--yes`).
## Uninstall
Two levels, choose as needed:
### Remove individual skills
```bash
# list registered skills
dsh-skills-nexus list
# remove one (deletes symlink, clone directory, and unregisters)
dsh-skills-nexus remove <skill-name>
```
The skill disappears from the DSH catalog on the next reload. All other
registered skills are unaffected.
### Uninstall nexus itself
```bash
# 1. (optional) remove all managed skills first, cleaning ~/.dsh/skills-nexus/
dsh-skills-nexus remove <name1>
dsh-skills-nexus remove <name2>
# ...
# 2. remove the plugin from the DSH profile
dsh plugin --profile web remove dsh-skills-nexus
# 3. (optional) delete leftover state
# macOS / Linux:
rm -rf ~/.dsh/skills-nexus
# Windows PowerShell:
# Remove-Item -Recurse -Force ~/.dsh/skills-nexus
# 4. (optional) delete the local test directory
# Windows PowerShell:
# Remove-Item -Recurse -Force dsh-skills-nexus
```
Restart the DSH profile. The `dsh-skills-nexus` CLI and all its skills will be
removed.
## Local testing steps
You can fully test nexus on your machine without pushing to GitHub or
publishing to npm. Follow these five steps.
### Step 1 — build the project
Inside the `dsh-skills-nexus/` directory:
```bash
cd dsh-skills-nexus
npm install
npm run build # generates lib/
```
> If you've made changes and want to verify types before building, run
> `npm run typecheck` (type-check only, no output).
### Step 2 — create a local overlay
Create `overlay.yml` in the project root (note: **do not commit this to git**,
it's for local development only):
```yaml
# overlay.yml
- insert:
- id: dsh-skills-nexus
# Windows: '/C:/your/path/dsh-skills-nexus/lib/index.js'
# macOS: '/Users/your/path/dsh-skills-nexus/lib/index.js'
# Linux: '/home/your/path/dsh-skills-nexus/lib/index.js'
name: '/your/absolute/path/dsh-skills-nexus/lib/index.js'
```
> `name` should be the **absolute path** to `lib/index.js`. On Windows, prefix
> the drive letter with `/`, e.g. `'/C:/dev/dsh-skills-nexus/lib/index.js'`;
> on macOS / Linux, use a standard absolute path, e.g.
> `'/home/user/dsh-skills-nexus/lib/index.js'`.
**Or generate it with a one-liner** (make sure you've cd'd into the project dir):
**Windows (Git Bash / MINGW):**
```bash
cat > overlay.yml <<EOF
- insert:
- id: dsh-skills-nexus
name: '/$(pwd -W)/lib/index.js'
EOF
```
> `pwd -W` outputs a Windows-style absolute path (e.g. `C:/Users/xxx/dsh-skills-nexus`).
> You must prefix it with `/`, resulting in `/C:/Users/xxx/dsh-skills-nexus/lib/index.js`.
> Node.js ESM loader doesn't accept bare `C:/...` paths on Windows (treats `c:` as a
> protocol) — it must be `/C:/...` or `file:///C:/...`.
**macOS / Linux:**
```bash
cat > overlay.yml <<EOF
- insert:
- id: dsh-skills-nexus
name: '$(pwd)/lib/index.js'
EOF
```
> `pwd` outputs a Unix-style absolute path (e.g. `/Users/xxx/dsh-skills-nexus`),
> which already starts with `/`, resulting in `/Users/xxx/dsh-skills-nexus/lib/index.js`.
### Step 3 — start DSH in patch mode
```bash
npx @deepseek-ai/dsh web --patch overlay.yml
```
This mounts nexus as a temporary layer in the current profile, making the
`dsh-skills-nexus` CLI command available. **After changing code, re-run
`npm run build` and restart DSH to pick up changes.**
### Step 4 — add a skill and test with the CLI
> **Note**: do **not** move the project folder during local testing. If you
> move it after `npm link`, re-running `npm link` will fail with
> `EEXIST: file already exists` — the global link still points to the old
> location. See the fix below.
Open another terminal:
```bash
# link the CLI globally for easy access
cd dsh-skills-nexus
npm link
# add a real skill repo to test with
dsh-skills-nexus add github:xiaxi626/theme-port-skill
# verify it was registered
dsh-skills-nexus list
# check that symlinks were created in the official root
ls -la ~/.dsh/skills/
```
**If you moved the folder and `npm link` fails with EEXIST:**
Option A — overwrite with `--force` (simplest, works on all platforms):
```bash
npm link --force
```
Option B — manually remove stale global links, then re-link:
**Git Bash:**
```bash
rm -f "$(npm prefix -g)/dsh-skills-nexus"
rm -f "$(npm prefix -g)/dsh-skills-nexus.cmd"
rm -f "$(npm prefix -g)/dsh-skills-nexus.ps1"
npm link
```
**Windows PowerShell:**
```powershell
Remove-Item -Force "$(npm prefix -g)\dsh-skills-nexus*"
npm link
```
> Using `$(npm prefix -g)` instead of `~` or hardcoded paths ensures
> the correct global npm directory is resolved regardless of `HOME`
> misconfiguration in Git Bash.
### Step 5 — verify in DSH
> **Note**: the DSH process started in Step 3 with `--patch` was running
> **before** you added a skill in Step 4, so asking "what skills do you have?"
> in the original DSH session won't show the new skill — the provider hasn't
> scanned it yet.
>
> **You must stop and restart**: go back to the terminal from Step 3, press
> `Ctrl+C` to stop the process, then re-run:
> ```bash
> npx @deepseek-ai/dsh web --patch overlay.yml
> ```
> After restart, DSH reloads the filesystem provider, which scans
> `~/.dsh/skills/` for symlinks and discovers the skill you just added.
Once restarted, ask "what skills do you have?" or similar in the DSH session,
and check whether `theme-port-skill` appears in the skill list.
---
## Lighter verification (without starting DSH)
If you just want to verify the "clone + symlink creation + list" pipeline
without starting DSH, use the CLI directly:
```bash
# add a skill
dsh-skills-nexus add github:xiaxi626/theme-port-skill
# check registration
dsh-skills-nexus list
# verify symlinks were created
ls -la ~/.dsh/skills/
```
> If `list` shows the expected skill and `ls -la` shows symlinks pointing to
> `repos/` directories, the clone + symlink pipeline is working correctly.
---
## Notes & limitations
- **`add` then visibility**: newly added skills appear after DSH rescans
`~/.dsh/skills/`. If the profile was already running, reload it — the
official filesystem provider will rescan the skills root and pick up newly
created symlinks.
- **Version pinning & updates**: pin a ref with `#branch`, `#tag`, or
`#commit-sha`. At install time the manifest records the exact resolved
commit (`commit`) — a lightweight lock that `list` shows. `update` only
fast-forwards **branch**-pinned skills (printing the commit change);
**tag/commit**-pinned skills are fixed points: it verifies the checkout
still matches the pin (and restores it if it drifted) instead of pulling, so
a pinned version never silently drifts. When no `#ref` is given, the CLI
detects the remote's default branch via `git ls-remote --symref` (falls back
to `main`).
- **Skill content repos only**: this is *not* a replacement for `dsh plugin add`
of real Cordis plugins. If a repo already ships a `dsh.bundle.patch`, install
it the normal way — nexus is for repos that don't. See
[nexus vs `dsh plugin`](docs/nexus-vs-plugin.md) for the full decision guide.
- **Collection repos & `--subdir`**: collection repos (skills nested under
subdirectories, e.g. `trae-community/trae-skills`) are installed piecemeal
with `--subdir <path>` — each install is its own entry with its own clone
(independent-clone design, see [docs/subdir-design.md](docs/subdir-design.md)
for the P1/P2 trade-off). Installing the whole repo without `--subdir` is
guarded by a confirmation prompt above 20 skills.
- **Flat-markdown filter**: a flat `*.md` file without frontmatter `name` AND
`description` is not treated as a skill — collection-repo docs like
`README.zh-CN.md`, `CONTRIBUTING.md` or `community-leaderboard.md` are never
"fake-installed". Doc-like names (`readme*`, `contributing*`, `license*`,
`changelog*`, `code-of-conduct*`, `security*`) are skipped at discovery.
- **Name collisions**: DSH indexes skills by name; a later install with the
same name overwrites. Use `--name` to distinguish entries, or `--subdir` to
install only what you need. enable/disable work per entry, `remove` deletes
the whole entry's clone and all its symlinks.
- **Skill name validation**: DSH requires lowercase kebab-case skill names
(`[a-z0-9]+` segments separated by single `-`). nexus normalizes invalid
frontmatter names at `add` time (converted to kebab-case) and warns with `⚠`.
- **Build scripts**: because nexus clones content repos itself (not via pnpm),
it sidesteps pnpm `allowBuilds` interception entirely.
- **Windows links**: nexus creates directory junctions on Windows
(`symlink(..., 'junction')`) and plain directory symlinks elsewhere — neither
needs Developer Mode or admin privileges.
## Documentation
- [Architecture — data flow, directory layout, SKILL.md discovery](docs/ARCHITECTURE.md)
- [nexus vs `dsh plugin` — when to use which](docs/nexus-vs-plugin.md)
- [Subdir design — P1/P2 trade-off for collection repos](docs/subdir-design.md)
- [Verifying the version-lock feature (P0)](docs/verify-version-lock.md)
- [Verifying the clone-retry feature (P0)](docs/verify-clone-retry.md)
- [Verifying collection-repo support (P1)](docs/verify-collection-support.md)
- [Verifying the plugin-load contract (plugin add → dsh web cold boot)](docs/verify-plugin-install.md)
- [Contributing — project layout, testing & CI](CONTRIBUTING.md)
- [Changelog](CHANGELOG.md)
## Contributing
Contributions of all kinds are welcome — bug fixes, new commands, docs.
See [CONTRIBUTING.md](CONTRIBUTING.md) for project layout, local setup, and
quality gates.
Found a bug or have an idea?
[Open an issue](https://github.com/xiaxi626/dsh-skills-nexus/issues/new/choose)
— we use issue templates to make it easy.
## License
MIT
Install
dsh plugin --profile web add github:xiaxi626/dsh-skills-nexus
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-skills-nexus from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.