Skill Invocation and Routing
Invocation is an authority decision followed by a relevance decision. A good description helps the model choose; a good policy decides whether that choice is allowed.
Lesson 25 of 45Build~105 minutesPython (stdlib)
Before this: Lesson 24 of Phase 13 (Skill Discovery and Progressive Disclosure)
On this page
Learning Objectives
- Distinguish explicit user invocation, implicit model invocation, application invocation, and skill-to-skill invocation.
- Model human visibility and model eligibility as independent policy dimensions.
- Write routing descriptions with positive triggers and near-miss boundaries.
- Separate eligibility, selection, activation, argument binding, and execution in traces and tests.
- Adapt runtime-specific invocation fields without presenting them as portable frontmatter.
The Problem
You install a database-migration skill. The user can run it by name, but the model also sees its description and selects it when someone asks a general database question. The skill then proposes a schema change for a task that only needed an explanation.
You add user-invocable: false, expecting to block people from running it manually. In another runtime, that field is ignored. You add disable-model-invocation: true, expecting the skill to disappear entirely. In the runtime that understands it, the user can still invoke it explicitly.
Nothing is wrong with the field names. The model is wrong. "User can see it," "model can select it," "application can preload it," and "tools inside it can execute" are separate facts. A single boolean called invocable cannot express them.
Routing has a second failure mode. If descriptions are vague, several skills become plausible. If descriptions are stuffed with keywords, unrelated tasks trigger them. The catalog is a probabilistic interface: compact enough to fit, specific enough to route.
The Concept
Five channels can start the lifecycle
| Actor | Invocation shape | Typical use | Main risk |
|---|---|---|---|
| Human user | Names a skill in the UI or prompt | Deliberate workflow selection | User expects availability or authority the host does not grant |
| Model or autonomous agent | Selects a catalog entry from task context | Automatic expert procedure | False-positive routing |
| Application | Activates or preloads a skill through runtime code | Fixed product workflow | Hidden coupling to one host |
| Another skill or subagent | Requests an exact skill as a workflow dependency | Composition | Cycles, missing dependency, or context bleed |
| Evaluation harness | Activates an exact skill under a fixed scenario | Repeatable measurement | Tests the skill while accidentally bypassing the production policy under study |
The portable Agent Skills specification defines the package. It does not standardize one universal slash-command UI, implicit-routing flag, application API, or subagent lifecycle.
The five invocation stages
skill-invocation-stages
Use these words precisely:
- Eligible means policy permits this actor to request the skill.
- Selected means the user named it or a router judged it relevant.
- Activated means its instructions entered the working context.
- Executing means the agent began model or tool work under those instructions.
- Completed means the output met an independent success check.
A trace that records only skill_used=true hides the boundary where a failure happened.
Human and model invocation form a 2x2 matrix
| Human can invoke | Model can invoke | Mode | Suitable examples |
|---|---|---|---|
| Yes | Yes | Shared | Code explanation, test planning, documentation review |
| Yes | No | Human-only | Publish preparation, billing export, destructive cleanup plan |
| No | Yes | Model-only | Internal style guide, domain reference, automatic support procedure |
| No | No | Disabled or application-only | Staged rollout, deprecated package, programmatic preload |
The matrix is a policy model, not standard YAML.
One current host uses disable-model-invocation: true for the human-only row and user-invocable: false for the model-only row. The default is both. Another host uses agents/openai.yaml with allow_implicit_invocation: false to keep explicit invocation while disabling implicit selection. These are runtime adapters. Unknown hosts may ignore them.
The confusing detail matters: user-invocable: false does not mean "the model cannot use this." It removes direct user invocation in the host that defines it. disable-model-invocation: true does not mean "the skill is disabled." It removes model-initiated selection while keeping explicit user access.
Explicit invocation is identity-first
An explicit invocation supplies identity directly:
/release-readiness v2.4.0
or:
release-readiness check v2.4.0 without publishing
Current Codex interfaces document /skills for selection and plain skill names in requests for explicit invocation. Claude Code documents /skill-name and host-specific argument expansion. The exact syntax, menu visibility, quoting rules, and variable expansion belong to the host.
An explicit request still passes policy. Naming a skill should not bypass missing permissions, workspace constraints, approval gates, or runtime isolation.
Implicit invocation is description-first
For implicit routing, the model initially sees catalog metadata rather than the full body. The description is therefore the skill's routing interface.
Weak:
description: Helps with releases.
Over-broad:
description: Use for release, version, package, build, deploy, publish, tag, changelog, GitHub, CI, or software tasks.
Bounded:
description: Inspect an already prepared release candidate and produce a readiness report. Use when the user asks whether a version, tag, package, or image is ready to publish; do not use for ordinary build failures or feature development.
The bounded version contains:
- Capability: inspect a prepared candidate.
- Output: readiness report.
- Positive boundary: asks whether a release artifact is ready.
- Negative boundary: ordinary builds and development are out of scope.
Negative boundaries are useful when two nearby skills share vocabulary. They are not a replacement for near-miss evals.
Routing is classification with an abstain option
For a skill s and request x, imagine a router score:
score(s, x) = capability_match + trigger_match + context_match - exclusion_match - ambiguity_penalty
The exact scoring may be an LLM decision rather than arithmetic. The engineering principle still holds: selection should beat a threshold and a competing skill. When evidence is weak, abstain.
skill-routing-abstention
For high-impact skills, implicit routing may be inappropriate even with a strong description. Use human-only policy when the cost of a false positive exceeds the convenience of automatic selection.
Eligibility must precede ranking
Do not score every discovered skill, choose the strongest match, and check that one skill's policy afterward. A blocked top match would incorrectly prevent an eligible lower-scored candidate from being considered.
Use this order for implicit routing:
- Filter discovered skills by the requesting actor and the active host adapter.
- Score only the eligible candidates.
- Select the strongest eligible match if it clears the threshold and ambiguity rules.
- Abstain when no candidate is eligible or no eligible score is strong enough.
Suppose incident-triage scores 0.80 but its host extension disables model invocation. incident-review scores 0.55 and allows model invocation. The router should evaluate incident-review as the best eligible candidate. It should not choose incident-triage, deny it, and stop.
This ordering also keeps policy changes from altering the meaning of a relevance score. Eligibility defines the selection set. Relevance ranks that set.
Routing evals need near misses
Positive cases prove recall:
{"prompt":"Is version 2.4.0 ready to publish?","expected":"release-readiness"}
Clear negatives prove basic precision:
{"prompt":"Explain rotary position embeddings.","expected":null}
Near misses expose boundary quality:
{"prompt":"Why did today's package build fail?","expected":"build-diagnostics"}
The near miss shares package and build with the release skill but belongs elsewhere. A routing set made only of obvious positives and unrelated negatives will overstate quality.
Arguments have three representations
An invocation argument crosses several boundaries:
skill-argument-boundaries
At each boundary, preserve intent without treating text as code.
- The host parser decides command syntax and quoting.
- The skill receives bound text or variables according to host rules.
- The instructions validate required values and defaults.
- A tool call converts values to a typed schema and revalidates them.
Do not interpolate raw arguments into shell commands. Prefer a script invoked with an argument vector or a typed MCP tool.
Application invocation is explicit orchestration
A product can activate a skill because its workflow already knows the task type. For example, a pull-request review service can preload pull-request-risk-review after the user presses Review.
This removes routing uncertainty but creates a dependency on the runtime API. Keep that adapter outside the portable body:
skill-host-adapter
The skill should remain intelligible when opened by a different compliant client.
Skill-to-skill invocation is a tool-like edge
Suppose release-readiness asks for security-change-review when dependency files changed.
The caller should provide:
- the target skill identity;
- a bounded task and artifact paths;
- the expected response contract;
- the reason for invocation;
- a fallback if unavailable;
- a maximum depth or cycle rule.
{
"target_skill": "security-change-review",
"task": "Review dependency changes in the candidate diff",
"inputs": ["artifacts/release.diff"],
"expected": "risk-report.json",
"max_depth": 2
}
The second skill is not pasted blindly into the first. The host decides how to activate it and whether it shares context, runs in a fork, or returns through a tool result.
Context lifecycle is host-specific
After activation, the skill body may remain in the conversation, be summarized during compaction, or run in a delegated context. Tool allowances may last one turn while instructions persist longer. A subagent may receive the skill without the parent's entire history.
Do not write a skill that depends on an invisible lifetime assumption. Put durable outputs in files or typed state, make re-entry safe, and state what must be reloaded after interruption.
On resume, read `artifacts/release-readiness.json` if it exists.
Revalidate the candidate commit before continuing.
Do not repeat an external write whose idempotency key is already recorded.
Build It
code/main.py implements policy and routing as separate adapters.
The model includes:
Actorfor human, model, autonomous agent, application, skill, and harness callers;SkillMetadatafor routing identity;InvocationPolicyfor the human/model matrix;InvocationRequestandInvocationDecisionfor traceable inputs and outcomes;CorePolicyAdapterfor portable behavior with no host extensions;ExtensionPolicyAdapterfor recognized runtime fields;build_invocation_matrix(policy)for the 2x2 view;route_request(skills, request, adapter)for eligibility filtering before relevance ranking, selection, and denial.
Run it:
cd phases/13-tools-and-protocols/25-skill-invocation-and-routing
python3 code/main.py
python3 -m unittest discover -s code/tests -v
The demo prints one matrix and decisions for explicit human, implicit model, autonomous-agent, application, skill-composition, and harness channels. Its extension-adapter results show a blocked top lexical match being removed before an eligible alternative is ranked. It also includes exact-name allowlists. No model API is required. The deterministic router exists to make policy boundaries inspectable, not to claim that lexical matching reproduces production model routing.
Why core and extension adapters are separate
If one parser assigns meaning to every observed frontmatter field, it silently promotes runtime conventions into a fake standard. Separate adapters force the caller to name which host semantics are active.
The CorePolicyAdapter uses only application-supplied policy. The ExtensionPolicyAdapter recognizes an explicit set of host fields and records which field changed the decision.
Use It
Write an invocation contract before publishing a skill:
actors:
human: allow
model: deny
application: allow
skill: deny
explicit_name: release-readiness
arguments:
candidate: required
publish: fixed_false
ambiguity: ask_user
missing_dependency: stop
context:
durable_state: artifacts/release-readiness.json
max_composition_depth: 2
This contract is design documentation for adapters and tests. It is not portable SKILL.md frontmatter unless a standard explicitly adopts it.
Ship It
This lesson produces the skill-invocation-router bundle. It includes an invocation-model reference, an example host policy, and a non-executing CLI that evaluates one human, model, autonomous-agent, application, skill-composition, or harness request and returns a JSON decision with channel, adapter, score, and reason.
The one-request CLI is a policy probe, not a full trigger evaluation. Use the labeled positive and near-miss design in Lesson 27 to compute confusion counts, precision, recall, and repeated-run stability.
Exercises
- Create all four rows of the human/model matrix and write one legitimate use case for each.
- Add application-only activation to
CorePolicyAdapter. Prove that human and model callers remain denied. - Write ten near misses for a deployment skill. Each prompt must share vocabulary with the skill while belonging to a different workflow.
- Add an ambiguity margin between the top two routing scores. Return
askwhen the margin is too small. - Add a maximum composition depth to skill-to-skill requests and detect a two-skill cycle.
- Run the same labeled set through core and extension adapters. Explain every changed decision.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Explicit invocation | "Slash command" | An actor supplies skill identity directly, subject to policy |
| Implicit invocation | "The model chooses" | A router selects from eligible catalog metadata based on task context |
| User-invocable | "Humans can use it" | A host-specific menu or direct-invocation property, not a core field |
| Model-invocable | "The agent can use it" | Eligibility for implicit model selection under host policy |
| Invocation adapter | "Frontmatter parser" | Code that maps a host's fields and APIs into a declared policy model |
| Near miss | "Hard negative" | A non-triggering request that resembles a skill's intended inputs |
| Abstention | "No skill selected" | A deliberate routing result when evidence is absent or ambiguous |
Further Reading
- Optimizing skill descriptions for positive triggers, specificity, and evaluation.
- Evaluating skills for trigger and output eval design.
- OpenAI: Build skills for current Codex explicit and implicit invocation controls.
- Claude Code skills for one host's
user-invocable,disable-model-invocation, arguments, and delegated context.
Check yourself
Quick quiz
Which event is an example of programmatic skill activation from the host perspective?
- An evaluation harness selects a named skill for a scheduled scenario
- A user chooses a named skill in the host UI
- A model infers a skill from semantic relevance
- A catalog reads descriptions during discovery
Show the answer
A. An evaluation harness selects a named skill for a scheduled scenario Programmatic activation comes from runtime or harness control flow, such as an evaluation selecting an exact skill. Human selection is explicit user activation, while semantic matching is implicit model activation.
A host recognizes `user-invocable: false`. How should a portability guide describe that field?
- A filesystem permission bit
- A replacement for the skill description
- A host-specific invocation extension interpreted by an adapter
- A required field in every Agent Skill
Show the answer
C. A host-specific invocation extension interpreted by an adapter A particular host can assign meaning to an extension without making it universal. Portable tooling should preserve or explicitly adapt the field and avoid promising identical behavior in runtimes that do not recognize it.
What should an implicit model router do with a near-miss query below its activation threshold?
- Activate the alphabetically first skill
- Lower the threshold silently for that request
- Convert the query into a human slash command
- Decline activation and continue without the skill or request clarification
Show the answer
D. Decline activation and continue without the skill or request clarification Near-miss negatives are where over-triggering appears. A threshold is useful only if the router honors it, reports the non-activation, and allows normal reasoning or clarification to continue.
In the human/model 2x2, what does `human=true, model=false` mean?
- The skill has unrestricted tool authority
- A human may invoke it explicitly, but the model should not select it implicitly
- Only an evaluation harness may activate it
- The model may activate it only after a network request
Show the answer
B. A human may invoke it explicitly, but the model should not select it implicitly The axes describe activation channels, not permissions. This quadrant supports deliberate user selection while suppressing automatic model routing, which is useful for costly or disruptive workflows.
Why does an evaluation harness usually activate a skill by exact name?
- It makes descriptions unnecessary
- Exact naming grants sandbox escape privileges
- It isolates skill behavior from routing variance so repeated runs are comparable
- It proves all hosts share one command syntax
Show the answer
C. It isolates skill behavior from routing variance so repeated runs are comparable A harness often needs to test the skill itself, not the discovery model. Exact programmatic selection removes one source of variance; separate trigger evaluations can then measure implicit routing precision and recall.
Which design keeps invocation and authority correctly separated?
- Allow model activation only when the bundle contains a shell script
- If a user invokes a skill, approve every action it requests
- Route activation through host policy, then review each requested action under the permission model
- Let extension metadata replace filesystem and network policy
Show the answer
C. Route activation through host policy, then review each requested action under the permission model Activation decides whether instructions enter context. Permission review decides whether proposed reads, writes, commands, or network calls may occur. Keeping those gates separate prevents discoverability or invocation from becoming accidental authority.
Questions people ask
How do I stop an AI agent from running a skill on its own?
Most agent runtimes have a setting that blocks the model from picking a skill automatically while still letting a user call it by name. Field names and behavior differ by runtime, so test it on the host you actually use.
Why does my AI agent use a skill for the wrong request?
The skill's description is probably too broad. Describe when to use it and add near-miss cases where it should not be used, such as explaining a topic versus changing something. Then test with real requests that are close but different.
Lessons from AI Engineering from Scratch by Rohit Ghumare and contributors, MIT license. Notes for owners by Lozo. License