Install
$ agentstack add skill-chrishan17-skill-router-skill-router ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Skill Router
Create skill routers — single-entry-point skills that route to a group of related sub-skills.
A router lives alongside its sub-skills in the agent's skills directory. It does not move or modify the originals; it only adds a new routing skill on top.
When to use
- User wants to reduce clutter from too many individual skills
- User wants to group related skills under a single router (e.g. skill-a + skill-b + skill-c → my-router)
- User wants to refresh a router after sub-skills have been updated
- User wants to remove a router they no longer need
How routers work
.claude/skills/
skill-a/ ← original, untouched
skill-b/ ← original, untouched
skill-c/ ← original, untouched
my-router/ ← router created by skill-router
SKILL.md ← routes to ../skill-a, ../skill-b, ../skill-c
_manifest.json
The router's SKILL.md contains:
- A synthesised description (WHAT + WHEN + NOT-WHEN) covering all sub-skills
- A Dispatch section with relative references (
../skill-name/SKILL.md) - A Capabilities section with each sub-skill's full description
Workflow
Step 1 — Detect agent tool directories.
python /scripts/skill_router.py --list-skills
The script scans the current directory for known project-local skill directories using the explicit skillsDir values from upstream agents.ts (for example .agents/skills/, .claude/skills/, .cortex/skills/, or skills/ for OpenClaw). Do not derive project paths from global install locations because some tools use different local and global directory layouts.
To see only skills not yet assigned to any router:
python /scripts/skill_router.py --list-skills --ungrouped
Handle the result:
- None found — tell the user no agent tool directories were found, and suggest running from the project root or using
--skills-dir. - One found — tell the user which agent was detected and show its available skills. Example: "Detected Claude Code at
.claude/skills/with 12 skills: skill-a, skill-b, ..." - Multiple found — list all detected agents and ask the user which one to use. Use
--list-agents --jsonfor structured output. Re-run with--toolto scope to that agent.
Step 2 — Determine which skills to group.
Two branches depending on what the user asked:
Branch A — User already named the skills (e.g. "group skill-a, skill-b, and skill-c"):
Proceed directly to Step 3 with those skills.
Branch B — User wants suggestions (e.g. "I have too many skills", "help me organise"):
If the user has fewer than 4 ungrouped skills, skip the analysis and ask directly: "Which skills would you like to group together?" There's no value in a router for 2–3 skills.
Run immediately without asking which strategy:
python /scripts/skill_router.py --list-skills-full --json
Analyse the full frontmatter of every skill using the by-collection strategy:
> Look at each skill's name, description, tags, category, collection, and metadata. Identify clusters that appear to come from the same install set, product suite, or thematic domain. Skills whose descriptions all mention the same keywords, or that share the same category tag, or whose tags overlap, likely belong together. Propose one router per identified cluster. Skills that fit no cluster remain ungrouped.
Then run --list-strategies to fetch saved strategies and present results + all options in one message:
Here's how I'd group your skills (by collection):
• content-suite → translate, summarise, rewrite, format-markdown
• code-quality → lint, test-runner, security-scan
• (ungrouped) → skill-router, find-skills
Shall I create these routers? Or try a different grouping strategy:
1. By origin — group by author / provenance / maintainer family
2. Custom — describe your own grouping logic (I'll save it for future use)
[Only shown if saved strategies exist, e.g.]
3. content-first — "Group all writing/publishing skills together, keep utility tools separate"
If the user picks an alternative strategy, apply it and loop back to show updated results:
- By origin — group by who made or maintains the skills. Use
--list-skills-full --jsonand look at all available origin signals together:author,source,homepage,repository,collection, name patterns, and any consistent references in descriptions. Identify which skills clearly belong to the same maker, suite, or install source — whether that signal comes from a field or from the content itself. If all skills point to one origin, warn that this produces one large router and recommend by-collection instead. - Custom — ask user to describe their logic, apply it to the
--list-skills-full --jsondata, then offer to save:--save-strategy --strategy-description "..." - Saved strategy — apply its description as the grouping rationale against the same data.
Once the user confirms a set of groups, proceed to Step 3 for each group.
When you create routers using a saved or custom strategy, note the strategy name to the user so they know which strategy to re-apply after future skill installs.
Step 3 — Read sub-skill descriptions and synthesize the router description.
For each skill in the group, read its description field from its SKILL.md frontmatter. Then write the router description following "Generating the router description" below.
Step 4 — Preview and confirm with the user.
Run --dry-run first to generate the full SKILL.md preview without writing files:
python /scripts/skill_router.py \
--name \
--skills ,, \
--description "" \
--dry-run
Show the user the generated SKILL.md output alongside the plan:
I'll create a router called "" in / that routes to:
- , ,
Description: ""
[Preview of generated SKILL.md shown above]
Proceed?
Step 5 — Create the router.
Re-run the same command without --dry-run:
python /scripts/skill_router.py \
--name \
--skills ,, \
--description ""
Repeat Steps 3–5 for each router group.
Step 6 — Tell the user:
- Each router is available as
/ - Sub-skills can still be invoked directly (
/) - Run
/skill-routeragain to refresh a router after sub-skills are updated vianpx skillsor similar
Refreshing a router
When the user asks to refresh an existing router, follow the same description-generation flow as creation — do not reuse the router's existing description:
- Read the router's
_manifest.jsonto find its sub-skills, or ask the user which router to refresh. - For each sub-skill, read its current
descriptionfrom itsSKILL.mdfrontmatter. - Re-synthesize the router description from scratch following "Generating the router description" below.
- Run
--dry-runto preview, confirm with the user, then run without--dry-run:
python /scripts/skill_router.py \
--refresh \
--description ""
Naming the router
The router name becomes a slash command (e.g. /code-review, /content-pipeline). A bad name makes it hard to remember and invoke.
Rules:
- Name the domain, not the list. The name should express what the group collectively does or covers — not enumerate the skills inside it.
- Good:
code-review,content-pipeline,data-tools - Bad:
skill-a-skill-b-skill-c,skill-group-1
- No vague catch-alls. Words like
misc,other,general,utils,tools(alone),unknown,stuffare not acceptable as the entire name. They carry no information.
- Bad:
misc-skills,other-tools,general - If skills truly don't share a domain, they shouldn't be in the same router.
- Suite prefix is acceptable — but add a domain suffix. If skills clearly come from a named suite, the suite name can be a prefix, but it must be followed by what the suite does.
- Good:
-content,-image-tools - Acceptable:
-suite(only when the suite itself is the identity and all skills are from it) - Bad: `` (too bare — says nothing about capability)
- Author alone is not a name. Author usernames or company names are not router names. A router name must say something about what the skills do.
- When in doubt, ask "what would a user type to invoke this?" If the name wouldn't help them recall when to use it, rename it.
Quick reference:
| Situation | Good name | Bad name | |-----------|-----------|----------| | Code analysis & review skills | code-review | code, misc-tools | | Skills from a named suite | -social, -images | `, suite-stuff | | Quality-focused skills | code-quality or design-quality | quality, misc-quality | | Skills from one author | -writing | , author-tools | | No clear shared theme | (don't create a router) | other-skills` |
Generating the router description
The router description is the most important part — it's what the LLM uses to decide whether to trigger this router. A weak description means wrong routing. Write it yourself based on the sub-skills' actual content.
Structure: WHAT + WHEN + NOT-WHEN (total ≤ 1024 characters, no markdown)
WHAT (1 sentence)
Summarise the problem domain this router covers — what class of user problem does it address?
Do NOT:
- Verbify skill names ("for linting code, scanning for issues, running tests...")
- Include origin or provenance ("from the X suite", "by ")
- Include implementation details ("uses OpenAI, Gemini, etc.")
Do:
- Write a domain statement that stands alone — someone unfamiliar with the skills should understand what this router is for
- Vary the sentence structure; avoid always defaulting to "A suite of X tools for Y"
Example:
Tools for reviewing and improving code quality, covering static analysis, test coverage, and security scanning.
WHEN (1-2 sentences)
Answer: what does a user say or ask when they need this router?
Critical rule: write user intent, not skill actions.
For each sub-skill, ask "what problem is the user trying to solve?" — not "what does this skill do?" These are different questions. Use the sub-skill's trigger phrases as a starting point, then rephrase them in the user's voice.
| Skill-action framing (bad) | User-intent framing (good) | |---------------------------|---------------------------| | "run static analysis" | "find bugs in my code" / "check for issues before shipping" | | "translate content" | "convert this to another language" / "make this multilingual" | | "format or convert markdown" | "clean up my article" / "prepare this for publishing" | | "normalize to design system" | "make this consistent with the rest of the app" |
- Do NOT name specific backends, APIs, or implementation choices unless the user would explicitly search for them by name
- Avoid vague phrases like "when the user needs help with X"
Example (good):
Use when the user wants to check their code for bugs, run tests, catch security issues, or get a thorough review before shipping.
Example (bad — skill-name verbing):
Use when the user wants to lint, test, scan, or analyse their code.
NOT-WHEN (1 sentence)
Name adjacent skills or task types that should NOT be displaced:
Do NOT use for , , or .
Example:
Do NOT use for writing new code from scratch, managing deployments, or generating documentation.
Constraints
- Total length ≤ 1024 characters
- No markdown (goes into YAML frontmatter
description: >) - Factually accurate — only claim what the sub-skills actually do
- If unsure about a sub-skill's purpose, re-read its full SKILL.md body
Command reference
| Command | Usage | |---------|-------| | List skills | skill_router.py --list-skills | | List ungrouped skills | skill_router.py --list-skills --ungrouped | | List skills (full frontmatter) | skill_router.py --list-skills-full --json | | List routers | skill_router.py --list-routers | | List detected agents | skill_router.py --list-agents | | Preview router (no write) | skill_router.py --name --skills , --description "..." --dry-run | | Create | skill_router.py --name --skills , --description "..." | | Create with description file | skill_router.py --name --skills , --description-file | | Force overwrite | skill_router.py --name --skills , --force | | Refresh | skill_router.py --refresh --description "..." | | Add skill | skill_router.py --add-skill | | Remove skill | skill_router.py --remove-skill | | Delete | skill_router.py --delete | | Rename router | skill_router.py --rename | | Save strategy | skill_router.py --save-strategy --strategy-description "..." | | List strategies | skill_router.py --list-strategies |
Common options: --tool (multi-agent), --json, --skills-dir .
Error handling
| Error | Cause | Fix | |-------|-------|-----| | Router already exists | --name matches existing dir | Use --refresh or --delete first | | Invalid router name | Not kebab-case (e.g. "My Router!") | Use lowercase + hyphens only | | Duplicate skill names | Same skill listed more than once in --skills | Remove duplicates before creating the router | | Skill not found | Skill folder doesn't exist in skills dir | Check spelling; use --list-skills | | No SKILL.md | Skill folder exists but has no SKILL.md | Reinstall the skill | | No manifest | --refresh/--delete on a non-router dir | Only managed routers supported | | No agent found | No tool dirs in current directory | Run from project root, or use --skills-dir | | Skills directory not found | --skills-dir path doesn't exist | Check path spelling; must be an existing directory | | Name conflict with existing skill | --name matches a non-router skill dir | Choose a different name; routers can't overwrite regular skills | | Skill already in router | --add-skill targets a skill already in the router | No action needed; check with --list-routers |
Reference
references/supported-agents.md— upstream-aligned agent registry and local/global path matrixreferences/best-practices.md— Agent Skills Specification checklistscripts/skill_router.py— router create/refresh/add-skill/remove-skill/delete/listscripts/scan_skills.py— agent detection and skill scanning (used internally)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: chrishan17
- Source: chrishan17/skill-router
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.