๐ธโโ๏ธ dsh-skill-router
August 17, 2026 ยท View on GitHub
๐ธโโ๏ธ dsh-skill-router
Rule-first pre-step skill routing for DeepSeek Harness: pours matched skills, stays silent when unsure.
Companion executor to 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 indefault-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 ยท How it works ยท What you get ยท Quick start ยท See it in action ยท Policy ยท Tested ยท Scope & non-goals ยท FAQ ยท Layout ยท License
๐ค 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 indefault-policy.yaml). First match wins. - On a hit: pours the matched skill bodies into the step as
skill-invocationmessages โ 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
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.
๐งญ Policy
# ~/.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;
pourlists 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 ยท bundled defaults: default-policy.yaml ยท walkthrough: 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 and the gold-task list in 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.
whenToUsefrontmatter 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
- Quickstart
- DeepSeek Harness repo
- Policy companion: skill-bartender
This repo is tagged
dsh-pluginand listed in the awesome-dsh-plugin curated list. PRs, issues and translations are welcome.