Skill Discovery, Selection and Routing¶
Why do we need skill discovery?¶
With one skill, there is no routing problem:
request → one known skill
As the system grows:
Agent Runtime
├── PR Review Skill
├── Test Failure Analysis Skill
├── Documentation Skill
├── Incident Triage Skill
├── Deployment Health Skill
├── Support Ticket Skill
└── ...
we need to answer:
How does the runtime know which capability is relevant to a request?
This is the skill discovery and routing problem.
Routing is not only a model problem. A good system applies deterministic filters and policies before a model ever selects a skill.
Skill registry / catalog¶
A useful mental model:
Skill Registry
├── name
├── version
├── description
├── input contract
├── output contract
├── capabilities / tags
├── risk level
├── required permissions
├── environment constraints
└── status: experimental | stable | deprecated
Example:
name: review_pull_request
version: 2.1
description: Review a pull request for correctness, architecture, regressions and missing tests.
tags: [github, code-review, read-only]
risk: low
requires:
- repository.read
The registry may be static configuration, a code registry, a database, or a runtime discovery service.
The important point is that the runtime needs more than skill names; it needs metadata required for selection.
Skill descriptions are interface metadata¶
If an LLM router selects from descriptions, their quality matters.
Weak:
Handles code stuff.
Better:
Reviews an existing pull request for correctness, architecture risks, regressions and missing tests. Read-only. Does not modify code.
This says:
- what the skill does,
- what it does not do,
- its scope,
- its side-effect profile.
A description is therefore not marketing text; it is part of the routing contract.
Routing pipeline: filter first, semantic selection second¶
A safer flow:
All registered skills
↓
status filter
↓
environment filter
↓
permission filter
↓
risk / policy filter
↓
relevant candidate skills
↓
router
↓
selected skill / no skill / ambiguity
Avoid:
LLM sees every skill
↓
chooses dangerous production skill
↓
application later discovers user has no permission
Prefer:
user permissions
↓
capability filtering
↓
LLM never sees unauthorized skill
This is least privilege at discovery time.
Routing strategies¶
There is no single best strategy.
1. Deterministic/static routing¶
Example:
HTTP endpoint /review-pr
↓
PR Review Skill
or:
request.type == INCIDENT
↓
Incident Triage Skill
Benefits:
- fast,
- cheap,
- deterministic,
- easy to debug.
If the caller already knows which skill is needed, there is no reason to insert an LLM router.
2. Rule-based routing¶
For example:
source == github && object == pull_request → PR skills
source == pagerduty → incident skills
This is a useful pre-filter.
3. Semantic / embedding routing¶
A shortlist can be built from embedding similarity between the user intent and skill descriptions.
user request
↓
embedding similarity
↓
top 3 candidate skills
This can be an efficient first-stage filter for a large registry.
Similarity, however, is not the same as authorization or task correctness.
4. Model-assisted routing¶
The model receives a shortlist:
Available:
- review_pull_request
- analyze_test_failure
- update_documentation
and returns a structured decision:
{
"skill": "analyze_test_failure",
"confidence": 0.86,
"reason": "The request is about a failing integration test."
}
This is flexible but probabilistic.
5. Hybrid routing¶
A common production pattern is:
Deterministic permission/environment filters
↓
Semantic shortlist
↓
LLM selection among 3-5 candidates
↓
validation
The model does not need to reason over the entire capability universe.
Router output should be more than a skill name¶
Useful structured result:
{
"decision": "SELECT_SKILL",
"skill": "review_pull_request",
"confidence": 0.88,
"missing_inputs": ["pull_request_number"]
}
Other outcomes can include:
{
"decision": "NO_MATCH"
}
or:
{
"decision": "AMBIGUOUS",
"candidates": ["incident_triage", "deployment_health"]
}
This is better than forcing a selection every time.
“No skill” is a legitimate decision¶
The router must be able to say that no skill applies.
If the contract says:
choose exactly one of A, B, C
then the model is forced to select something.
User request:
Write a short birthday poem.
Available skills:
PR Review
Incident Triage
Deployment Health
Correct routing:
NO_MATCH
not Incident Triage simply because one choice is required.
Ambiguity and clarification¶
User:
Find out what is wrong with payment-service.
This could mean:
- production incident diagnosis,
- deployment health check,
- code analysis,
- test failure.
The router may request clarification:
{
"decision": "NEEDS_CLARIFICATION",
"question": "Do you want to investigate the running production service, a deployment, or the source code?"
}
This is better than launching the wrong capability automatically.
Confidence is not policy by itself¶
A value such as:
confidence = 0.84
is not automatically a calibrated probability.
It can be a routing signal, but thresholds should come from evaluation.
For example:
high-confidence routing → auto select
medium → ask clarification / second-stage router
low → no match
should use measured boundaries rather than intuition.
Permission-aware discovery¶
Suppose the registry contains:
read_deployment_health
restart_deployment
A read-only user should receive a registry projection containing only:
available skills:
- read_deployment_health
The restart skill is not merely rejected at execution time; it is not selectable in the first place.
Global registry
↓
user/environment policy
↓
Authorized skill view
↓
router
This reduces both accidental and malicious routing opportunities.
Environment-aware routing¶
A skill can declare:
environments: [dev, staging]
or:
production: approval-required
The runtime can filter accordingly.
For a local coding agent, a capability such as:
run_shell_in_sandbox
may be available, while a production support agent should not receive it.
Skill selection vs tool selection¶
These are different layers.
User request
↓
Skill routing
↓
Deployment Health Skill
↓
Tool selection inside skill
↓
query_metrics / get_deployment / read_events
The router selects a task-level capability.
Skill execution selects tool-level capabilities.
Flattening both levels can produce an enormous tool list for the model.
Hierarchical capability discovery¶
For large systems, hierarchy can help:
Domain Router
├── Engineering
├── Support
└── Finance
Engineering Router
├── PR Review
├── Test Analysis
└── Deployment Health
Every model call does not need to see 300 skill descriptions.
This is similar to namespace and modularization problems in normal software.
Example: support-agent routing¶
Available skills:
invoice_lookup
refund_recommendation
account_access_diagnosis
subscription_change_explanation
User:
You charged the same amount twice.
Possible flow:
1. permission filter
2. all support skills remain
3. semantic router → invoice/refund candidates
4. LLM router → invoice_lookup first
5. execute read-only lookup
6. based on result, workflow/agent may later invoke refund recommendation
One routing decision does not necessarily solve the entire user problem.
Routing and skill composition¶
The router should not try to plan the entire workflow when it only needs to select the next capability.
For example:
request
↓
select invoice_lookup
↓
new evidence
↓
select refund_recommendation
This approaches an agentic loop.
Skill routing and multi-step planning are separate concepts.
Anti-pattern: every skill is always available¶
300 skills
+ every tool
+ every permission
→ one prompt
This is:
- noisy,
- expensive,
- harder to choose from,
- a larger security attack surface,
- more prone to tool confusion.
Prefer candidate filtering and shortlists.
Anti-pattern: routing by skill name only¶
skill_42
helper_x
smart_fix
The router has no stable semantic contract.
Names and descriptions should be explicit and discriminative.
Anti-pattern: delegating authorization to the router¶
Weak:
Prompt:
"Do not select admin skills for normal users."
Better:
application removes unauthorized skills
↓
router only sees permitted candidates
Anti-pattern: forced selection¶
If exactly one skill must always be selected, the system manufactures false competence.
Support outcomes such as:
NO_MATCH
AMBIGUOUS
NEEDS_CLARIFICATION
Takeaways¶
- A skill registry is more than a list; selection may require metadata, contracts, risk, and permission information.
- Skill descriptions are part of the routing interface, so make them precise and discriminative.
- Before routing, deterministically filter by permission, environment, status, and policy.
- If the caller already knows the skill, use direct routing.
- A strong pattern for larger systems is hybrid routing: filter → shortlist → model-assisted selection.
NO_MATCHandAMBIGUOUSare legitimate outcomes.- Use confidence thresholds only when backed by evaluation.
- Skill selection and tool selection are different abstraction levels.
- Hierarchical routing can reduce context and confusion in large registries.
- The router must never be the authorization authority.