Bundle
dsh-skill-router
Pre-step skill router for DeepSeek Harness: rule-first task-to-skill matching that pours matched skill bodies only on high-confidence hits and stays silent otherwise. Companion to skill-bartender.
- Source
- MJorgin
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 14 days ago
Readme
<div align="center">
<img src="docs/social-preview.png" alt="dsh-skill-router โ rule-first pre-step skill routing for DeepSeek Harness" width="100%">
<br>
# ๐ธโโ๏ธ dsh-skill-router
### *Rule-first pre-step skill routing for DeepSeek Harness: pours matched skills, stays silent when unsure.*
[](LICENSE)
[](https://github.com/akqwpeter-prog/dsh-skill-router/actions/workflows/test.yml)
[](https://github.com/topics/dsh-plugin)
[](README.md#-how-it-works)
[](README.md#-how-it-works)
[](https://github.com/akqwpeter-prog/skill-bartender)
[](docs/lang/README_ZH.md)
<br>
Companion executor to [skill-bartender](https://github.com/akqwpeter-prog/skill-bartender):
the skill carries the policy *judgment*, this plugin carries the *execution*.
Deterministic, **zero LLM calls, zero token cost** until a rule actually pours:
- โก **Pre-step hook** โ reads the latest user message before every step.
- ๐งญ **Rule-first matching** โ user-editable YAML policy (`~/.dsh/skill-router.yaml`,
bundled defaults in `default-policy.yaml`), first match wins.
- ๐ **Silent miss** โ no hit โ zero intervention; the model keeps its normal
catalog flow.
- โป๏ธ **Once per session** โ each skill pours at most once.
- ๐ก๏ธ **Broken YAML never breaks the session** โ falls back to bundled defaults.
[Why](#-why) ยท [How it works](#-how-it-works) ยท [What you get](#-what-you-get) ยท [Quick start](#-quick-start) ยท [See it in action](#-see-it-in-action) ยท [Policy](#-policy) ยท [Tested](#-tested) ยท [Scope & non-goals](#-scope--non-goals) ยท [FAQ](#-faq) ยท [Layout](#-layout) ยท [License](#-license)
[**English**](README.md) ยท [**็ฎไฝไธญๆ**](docs/lang/README_ZH.md)
</div>
---
## ๐ค Why
Most skill loading is left to the model's judgment: it sees the catalog every
step, re-decides every time, and often loads late, wrong, or not at all. A
router that runs *before* the model answers fixes that:
| | dsh-skill-router | LLM-judge router | Manual loading |
|---|---|---|---|
| Decision maker | **rules** (deterministic) | LLM / embeddings | the model, per step |
| Token cost | zero until a rule pours | every step | every step |
| Latency added | ~0 ms | model round-trip | n/a |
| Reproducible | โ
same message โ same pour | โ varies | โ varies |
| User control | edit YAML, done | prompt it | hope it remembers |
**Why rules and not an LLM judge?** Speed, cost, and predictability. A
URL-path rule routes `feishu.cn/x/docx/` to `lark-doc` in microseconds, for
free, every time โ and `skill-bartender`'s routing table is where the policy
*judgment* lives. This plugin is the muscle, not the brain.
## โ๏ธ How it works
- Hooks `agent/pre-step`, reads the latest user message.
- Matches it against user-editable rules (`~/.dsh/skill-router.yaml`, bundled
defaults in `default-policy.yaml`). First match wins.
- On a hit: pours the matched skill bodies into the step as
`skill-invocation` messages โ the catalog's "already loaded, don't
re-load" rule applies automatically.
- No hit: zero intervention. The model keeps its normal catalog flow.
- Each skill pours at most once per session.
## โจ What you get
| Capability | What it does |
|---|---|
| โก Pre-step hook | `agent/pre-step` โ the pour happens *before* the model starts thinking |
| ๐งญ YAML policy | User-editable `~/.dsh/skill-router.yaml`; broken YAML falls back to bundled defaults |
| ๐ `whenToUse` triggers | Installed skills' `whenToUse` frontmatter acts as a secondary trigger (literal phrase match, appended after YAML rules) |
| ๐ Zero cost | No LLM judge, no embeddings โ rules only (fast, free, deterministic) |
| โป๏ธ Once per session | Dedupes pours per session; no skill body floods the context |
| ๐ Companion | Works with skill-bartender's routing table and taste test |
## โก Quick start
```sh
dsh plugin --profile web add github:akqwpeter-prog/dsh-skill-router
```
Then restart the running instance (profile bundles load at boot).
Verify: say "็ๆไธๅผ ๆตทๆฅ" โ `media-tools` pours automatically; say "่ฟไธชๆชๅพๅธฎๆๆฃๆฅไธไธ" โ `vision-review` pours. No rules matched? The model just works as usual.
## ๐ธ See it in action
*One picture: a rule hits โ the skill pours before the model answers; no hit โ total silence.*
<img src="docs/screenshots/how-it-works.png" alt="How the router works: agent/pre-step reads the message โ rule match (YAML first, then whenToUse) โ hit? โ pour skill-invocation (once per session) or stay silent (zero tokens)" width="100%">
## ๐งญ Policy
```yaml
# ~/.dsh/skill-router.yaml
rules:
- match: "(็ๆ|็ป).{0,12}(ๅพ|ๆตทๆฅ|banner)"
pour: [media-tools]
```
- Ordered by precision: URL-path routing first, media, delegation, workflow
skills before atomics.
- First matching rule wins; `pour` lists the skill names to load.
- Broken YAML falls back to bundled defaults and never breaks the session.
- Write it as data: improve matching by editing YAML, not code.
- Full reference: [docs/POLICY.md](docs/POLICY.md) ยท bundled defaults: [default-policy.yaml](default-policy.yaml) ยท walkthrough: [docs/EXAMPLES.md](docs/EXAMPLES.md).
## ๐งช Tested
Integration suite (10 cases) run against a live profile: pour, dedupe,
zero-touch, reject passthrough, URL routing, mail-vs-IM disambiguation,
false-positive guards. See `test/` in the repo, plus the design notes in
[DESIGN.md](DESIGN.md) and the gold-task list in [GOLD-TASKS.md](GOLD-TASKS.md).
## ๐ฏ Scope & non-goals
- No LLM judge, no embeddings: rules only (fast, free, deterministic).
- No auto-install of missing skills: that stays in skill-bartender's
quarantine โ SkillSpector โ human-approval flow.
- Rule table is data: improve matching by editing YAML, not code.
- `whenToUse` frontmatter on installed skills acts as a secondary trigger
(literal phrase match, appended after YAML rules). Write it as a short
trigger phrase; long prose never matches. Today's skill data mostly lacks
the field โ skill-bartender's taste test can backfill it.
## โ FAQ
**Does it consume tokens when nothing matches?**
No. No hit โ zero intervention, zero LLM calls. The router only reads text
already in the step and runs regex rules โ microseconds, free.
**How is it different from skill-bartender?**
skill-bartender is the *judgment* (which skill fits, when to stay silent, how
to install safely). This plugin is the *execution* (a deterministic pre-step
hook that pours). They complement each other; the router works standalone too.
**Can I use my own rules?**
Yes โ copy `default-policy.yaml` to `~/.dsh/skill-router.yaml` and edit.
First match wins; broken YAML falls back to defaults.
**Does it pour the same skill twice in one session?**
No โ each skill pours at most once per session, so context never floods.
## ๐บ๏ธ Layout
```
dsh-skill-router/
โโโ index.js # Cordis plugin: pre-step hook + pour logic
โโโ policy.js # rule loading / matching (unit-tested)
โโโ default-policy.yaml # bundled defaults (copy to ~/.dsh/skill-router.yaml)
โโโ test/ # policy unit tests + integration suite
โโโ DESIGN.md / GOLD-TASKS.md # design notes + gold tasks
โโโ docs/
โ โโโ screenshots/how-it-works.png
โ โโโ POLICY.md / EXAMPLES.md
โ โโโ social-preview.png # banner (regenerate via scripts/)
โ โโโ lang/README_ZH.md # ็ฎไฝไธญๆ
โโโ scripts/
โ โโโ make-banner.py # composes docs/social-preview.png
โ โโโ make-diagram.py # composes the how-it-works diagram
โ โโโ check-policy.mjs # policy validation
โโโ cordis.patch.yml / package.json # DSH bundle manifest
โโโ LICENSE (MIT)
```
## ๐ค Join the DSH plugin ecosystem
DeepSeek Harness developer preview is still in its testing phase for Harness
developers; core plugins and base APIs will keep iterating. We look forward
to exploring the upper limits of intelligence together with developers
worldwide, on top of open-source, open, reusable, and composable infrastructure.
- [dsh-plugin topic](https://github.com/topics/dsh-plugin)
- [Quickstart](https://deepseek-harness.github.io/deepseek-harness/guide/quickstart)
- [DeepSeek Harness repo](https://github.com/deepseek-ai/deepseek-harness)
- Policy companion: [skill-bartender](https://github.com/akqwpeter-prog/skill-bartender)
> This repo is tagged [`dsh-plugin`](https://github.com/topics/dsh-plugin) and
> listed in the [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
> curated list. PRs, issues and translations are welcome.
## ๐ License
[MIT](LICENSE)
Install
dsh plugin --profile web add github:MJorgin/dsh-skill-router
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-skill-router from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.