AI coding

Writing a Skill Router: How Models Choose Between Skills

Antonio Evans10 min read

A wide diagram of a request entering a model, fanning out to a row of skill description cards, each with a score and a checkmark or cross, and one card being pulled forward to load.
Key points

Key points

  1. 1A model does not read every skill in full: at startup it sees only each skill's name and description, and loads the body only after a match.
  2. 2Selection is a shortlist problem: the cost of a wrong shortlist is usually paid downstream, where planning and execution cannot recover the missing skill.
  3. 3A skill gets skipped for three different reasons, and each has a separate fix: missing vocabulary in the description, a stronger rival, or a threshold that filters it out.
  4. 4You can diagnose all three by logging the full candidate list and scores for a fixed query set instead of rereading your prompt.

How a model actually sees your skill library

Start with the constraint that shapes everything else. At startup an agent loads only the name and description from each skill's frontmatter, which the documentation estimates at about 100 tokens per skill, and reads the full SKILL.md body only when a task matches that description (the Agent Skills overview). VS Code's documentation describes the same behavior from the client side: skills are loaded on demand, so "only relevant content loads into context when needed" (VS Code agent skills docs).

That design is usually called progressive disclosure, and it is a context-window decision, not a routing decision. The specification allows a description of up to 1,024 characters, so a description is both the entire advertisement for a skill and the only thing the selector has to work with (the same guide). The authoring guidance is blunt about the consequence: "the description carries the entire burden of triggering" (Agent Skills description guide).

A worked token budget makes the trade-off concrete. With 40 installed skills at roughly 100 tokens of metadata each, the agent spends about 4,000 tokens before the first user turn on names and descriptions alone. That is affordable. At 400 skills it is about 40,000 tokens, and at that point you are paying for the catalog on every request whether it helps or not. The practical rule: metadata cost scales linearly with catalog size, so every description you add is a recurring cost, while every description you cut can silently disable a capability.

There is a second asymmetry that matters more for routing. In production stacks, the component that picks the shortlist can often inspect full skill text, while the agent that finally uses the skill usually sees only name and description. Once the wrong shortlist is surfaced, "downstream planning and execution have little chance to recover" (SkillRouter paper). That sentence should reframe how you debug: a failed task may be a retrieval failure, not a reasoning failure.

The selection pipeline, stage by stage

Most routers are assembled from the same four stages, even when the marketing names differ. The Patronus routing guide separates routing approaches into rule-based (keyword spotting and pattern matching), supervised machine learning on routing data, and LLM-based selection, with the last described as the state of the art for agent routing (Patronus AI agent routing guide). Production systems typically blend the first and third.

Stage 1, embedding. The request and every skill description are converted into vectors, and similarity is computed. This is cheap, runs against the whole catalog, and is good at paraphrase but blind to specifics that embeddings treat as noise, such as a product name or a file format.

Stage 2, keyword match. A lexical pass rewards exact terms. It catches "use the parquet loader" when the description says "parquet," and it is the reason a description with no shared vocabulary with the request almost never surfaces. Rule-based keyword routing is simple and inflexible, which is exactly what you want for a must-fire trigger (Patronus guide).

Stage 3, scoring and ranking. Scores from the passes are combined and sorted. In a two-stage retrieve-and-rerank design, a bi-encoder retrieves a shortlist (SkillRouter retrieves 20 candidates) and a cross-encoder reads the query alongside each candidate's name, description, and body to rerank them (SkillRouter paper).

Stage 4, threshold. The top candidate is loaded only if it clears a cut. Threshold is the parameter most likely to be set once and never revisited, and it is the one that most often causes silent, total failure.

StageSignal it usesTypical failureFirst fix to try
EmbeddingSemantic similarity of request and descriptionDescription paraphrases the domain but never names the user's wordsRewrite description in user vocabulary
Keyword matchExact term overlapRequest uses a synonym the description lacksAdd synonyms and file extensions explicitly
Scoring and rankingCombined score orderA sibling skill wins on shared vocabularyNarrow the rival's description or add a disambiguating clause
ThresholdMinimum score to loadCorrect skill scores highest but under the cutLog scores, then lower or calibrate the cut

For a selector that needs a hard trigger to fire regardless of scores, treat it as a routing rule rather than a retrieval problem. The classic mitigation is to separate capability identification from implementation selection: first decide which capability is needed, then choose among implementations registered under it (two-step tool selection disclosure). Applied to skills, that means one explicit capability mapping per request class, with rival skills demoted to implementations.

Why a well-written skill still gets skipped

There are four distinct failure modes, and mixing them up is why people rewrite a description that was never the problem.

The vocabulary gap. The request says "sales spreadsheet," the description says "tabular data ingestion." The embedding pass may bridge some of that, but the keyword pass will not, and the description guide is explicit that agents match against what the user asked for, so you should list contexts where the skill applies "even if they don't explicitly mention" the domain terms (Agent Skills description guide).

The stronger rival. Catalog reliability breaks at scale in a specific way: a new skill does not corrupt an old one, it "changed the decision boundary around it." The documented example is an operations agent where a new kubernetes-diagnostics skill wins a request about deployment errors over the existing incident-triage skill, because the newer description carries more lexical matches for "deployment" and "errors." Both skills may be defensible choices, but the wrong one was chosen, and the individual skill tests still pass (catalog reliability article).

The task that does not need a skill. Agents typically consult skills only for tasks that need knowledge or capabilities beyond what they can handle alone, so a simple one-step request may not trigger a skill even when the description matches perfectly (Agent Skills description guide). If you are testing activation with trivial requests, you are measuring nothing.

The threshold and the body gap. A good score that does not clear your cut is a configuration failure, not a wording failure. Separately, if you route on metadata only, you lose information that lives in the body. On a benchmark of about 80,000 candidate skills, hiding the skill body lowered Hit@1 from 68.0% to 24.0% for the strongest base pipeline, and metadata-only encoding trailed all-field encoding by 14.0 points even when trained on the same 37,979 pairs (SkillRouter analysis). Those numbers come from one heavy-overlap benchmark, so read them as "bodies matter more than you think in crowded catalogs," not as a universal law.

Diagnostic experiments you can run today

The description guide recommends building an eval set of about 20 queries, 8 to 10 that should trigger and 8 to 10 that should not, mixing formal and casual phrasing, explicit and implicit references, terse and context-heavy prompts, and single-step versus multi-step tasks (Agent Skills description guide). The most valuable negatives are near-misses: a CSV analysis skill should not fire on "update the formulas in my Excel budget" or on a database ETL request, because those share keywords but need a different capability.

Once you have the set, run four experiments. Log, do not guess.

Experiment 1, vocabulary audit. For each should-trigger query, record which words in the request appear in any skill description. If the domain noun in the request ("parquet," "postmortem," "invoice") never appears in any description, you have found a vocabulary gap without touching the model.

Experiment 2, score trace. Log the candidate list with scores and the threshold value. This single artifact separates "not retrieved" from "retrieved but ranked second" from "ranked first but under threshold," and each has a different fix.

Experiment 3, A/B the description only. Change nothing but the description, include both what the skill does and specific triggers for when to use it, then rerun the full set (Claude skill authoring best practices). Keeping everything else fixed is what makes the result attributable.

Experiment 4, remove a rival. Pull each competing skill out of the catalog one at a time and rerun. If activation recovers when a rival is removed, your problem is the decision boundary, not the skill.

A minimal harness looks like this: load every description from frontmatter, score the fixed query set, and print the top five with scores so regressions are visible in a diff.

import json, math, re

def tokens(text):
    return set(re.findall(r"[a-z0-9]+", text.lower()))

def jaccard(a, b):
    return len(a & b) / max(1, len(a | b))

skills = json.load(open("skill_descriptions.json"))
queries = json.load(open("eval_queries.json"))

for q in queries:
    qt = tokens(q["query"])
    ranked = sorted(
        ((round(jaccard(qt, tokens(s["description"])), 3), s["name"]) for s in skills),
        reverse=True,
    )[:5]
    print(q["should_trigger"], q["query"][:60], "->", ranked)

Run the same loop against your production router's actual scores where you can, since a hand-rolled metric only shows what lexical overlap sees.

Writing descriptions that win the shortlist

The description guide lists four principles, and each maps to a pipeline stage. Use imperative phrasing ("Use this skill when...") because the agent is deciding whether to act. Describe user intent, not internal mechanics, because the agent matches against what the user asked. Err on the side of pushy by listing contexts explicitly, including ones where the user does not name the domain. Keep it concise, since long enough to cover scope and short enough not to bloat context across many skills is the whole target, and the spec enforces a 1,024-character ceiling (Agent Skills description guide).

The authoring guidance adds a naming convention worth stealing: gerund-style names such as processing-pdfs or analyzing-spreadsheets, and never vague names like helper or utils, which carry no signal for either a human or a selector. It also stresses that the description should include both what the skill does and when to use it (Claude skill authoring best practices).

A comparison makes the difference concrete:

Weak descriptionStrong descriptionWhy it changes selection
"Helps with data files.""Use this skill to analyze CSV and Parquet exports: compute margins, detect outliers, and flag rows below a threshold, even if the user only says 'spreadsheet' or 'report.'"Names formats, verbs, and the implicit user vocabulary that drives keyword and embedding match
"Checks Kubernetes.""Use this skill when pods fail to schedule, services error after a rollout, or resource pressure appears. Do not use for general incident timelines; use incident-triage for that."Adds disambiguating negative scope that lowers the rival's win rate
"PDF tool.""Use this skill when extracting text and tables from PDFs, filling forms, or merging documents."Distinguishes the capability from adjacent document tasks

That third column is the decision rule: a description earns its tokens by containing words the request will use, not by describing the implementation well. One more boundary to respect: keep one skill focused on one outcome. Red Hat's applied AI team reports that broad, comprehensive skills are harder to route and maintain, and that splitting work between deterministic scripts and model reasoning cut cost by 26% in their experiments (Red Hat skill-building pitfalls). A skill that does five things has five sets of trigger words competing in one description, and loses all five races to five focused rivals.

Where routing meets context engineering

Skill selection is a small instance of a larger job. LangChain's framing is that agents usually fail for one of two reasons: the model is not capable enough, or "the 'right' context was not passed to the LLM," and that the second is more often the cause, which makes context engineering "the number one job of AI Engineers" (LangChain context engineering docs). A router that surfaces the wrong skill has passed the wrong context before the model writes a token.

That framing gives you a checklist that generalizes. For every request class, ask what context the model needs (a skill, a tool, a document), how that context is represented to the selector (name and description, or full text), what budget it consumes, and what happens when selection misses. The LangChain guide separates transient model context from persistent state and store, which is the right mental split for skills too: metadata is transient per call, the loaded body is a per-task decision, and bundled scripts and references are on-demand resources.

Progressive disclosure is a context optimization first, so it needs a spec: the body should be loaded on demand, and the parts a selector needs must reach it through summary. That is exactly why skill text is treated as a resource and not as prompt text. The practical implication is that when you fix a routing bug, you are usually improving a description or a spec, and that improvement helps every agent that reads it rather than one prompt.

Task routing itself is a generalized version of this. If you also route between agents or specialists, the routing patterns and evaluation metrics described for multi-agent systems (single-agent routing, multi-agent fan-out, hierarchical routing, and accuracy or recall checks against a labeled set) apply directly to skill selection with a change of vocabulary (Patronus AI agent routing guide). The same guide recommends logging, testing, and fallback mechanisms, and those three practices are what turn a router from a black box into something you can operate.

That is where a skills library becomes a shared asset rather than a personal folder. Installable skills with explicit metadata and routing-friendly descriptions are what make a catalog readable to an agent at scale, and the same discipline you apply to one description is what keeps a library honest. If your next step is comparing several models on routing or generation quality, doing it through one endpoint with consistent request shapes removes a variable from your experiments; Quanta Inference puts those models behind a single OpenAI-compatible key.

FAQ

FAQ

How many skills can an agent have before routing breaks?

There is no fixed number, but the cost curve is linear: about 100 tokens of metadata per skill at startup, so 400 skills is roughly 40,000 tokens of catalog before the request arrives (Agent Skills description guide). The bigger risk is overlap, since the documented failure is a new skill changing the decision boundary around an old one rather than the catalog simply being large (catalog reliability article).

Should I put full skill text into the selector?

Only if you can afford it and your catalog is crowded. Hiding the body cost 37 to 44 percentage points of Hit@1 across encoder and reranker baselines in an 80,000-skill benchmark, which argues for giving the router more than metadata when many candidates look plausible (SkillRouter paper). For a handful of sharply separated skills, metadata is usually enough.

Why does the skill trigger on requests it should not handle?

Usually because its description is too broad or it overlaps a neighbor on shared keywords. The fix is a near-miss eval set and a disambiguating clause that names the adjacent task and says to use another skill for it, then rerun the set (Agent Skills description guide).

Does a well-matched description guarantee the skill loads?

No. Agents typically consult skills only for tasks requiring knowledge or capability beyond what they can handle alone, so a trivial one-step request can skip a perfectly matching skill (the same guide). Your threshold also decides, which is why you should log the score rather than infer from the outcome.

When should a request be a hard route instead of a retrieval candidate?

When a missed skill is unacceptable, for example a compliance checklist or a mandatory validation step. Make the capability explicit and force the load, the way two-step selection splits capability identification from implementation choice (two-step tool selection disclosure), and let similarity ranking handle the rest.

Sources

Sources

  1. Optimizing skill descriptions
  2. Use Agent Skills in VS Code
  3. SkillRouter: Skill Routing for LLM Agents at Scale
  4. AI Agent Routing: Tutorial & Best Practices
  5. Tool Selection by Large Language Model (LLM) Agents
  6. Agent Skill Routing: Why Catalog Reliability Breaks at Scale
  7. SkillRouter: Skill Routing for LLM Agents at Scale
  8. Skill authoring best practices - Claude Platform Docs
  9. Building skills for AI agents: pitfalls and best practices
  10. Context engineering in agents - Docs by LangChain
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles