Agent Skills: Discovery, Invocation, Routing
Write, install, discover, invoke and route SKILL.md packages. Validators, catalogs, router and installer projects.
- Tasks and commands
- Annotated code
- Diagrams
- Comparisons
- Defaults and numbers
- Troubleshooting
- Questions and tips
Skill lifecycle#
Install, invoke, remove#
| Command | What it does |
|---|---|
npx skills add rohitg00/ | Installs the nested bundle with references, script and asset |
/ | Explicit invocation in a host with /skill-name syntax |
/ | Picks a skill by name in the Codex interface |
python3 <SKILL_ROOT>/ | Runs the bundled validator. Show argv, cwd and exit code |
npx skills remove skill-contract-reviewer | Removes the bundle. Use the same host and scope |
python3 scripts/ | Copies Phase 13 bundles and writes manifest.json |
python3 -m unittest discover -s code/ | Runs a lesson test suite |
Project runs and grading#
| Task | Code |
|---|---|
| Create a learner workspace | python3 scripts/ |
| Grade one stage | python3 scripts/ |
| Route the sample request | node learning-artifacts/ |
| Dry run an install | node learning-artifacts/ |
| Install for real | cli.ts install bundle.json agent root expected-source-digest |
| Build the validator | rustc --edition= |
| Validate and load in 2000 characters | validator projects/ |
| Check a reference solution | python3 scripts/ |
Writing rules#
namemust match the parent directory.- Description: one clause for the capability, one for the trigger boundary.
- Add a negative boundary when two skills share words. Test near misses.
- Filter by eligibility first. Then rank. Abstain when no score is strong enough.
- Do not interpolate raw arguments into shell commands.
- Name a dependency skill and a fallback. Stop when it is unavailable.
Questions#
- Skill or hook?
- A hook when every event must run. A skill for model judgment.
- Skill or MCP tool?
- A tool for a typed external capability. A skill for procedure.
- Does an explicit name bypass policy?
- No. It still passes every gate.
- Does the router run the skill?
- No. It emits plans and explanations only.
- Does a successful install prove activation?
- No. The agent must discover it.
Validate, catalog, disclose, route (lessons)#
report = validate_skill_text(text, directory_name, allowed_runtime_extensions=())select_primitives(task)code, skill, hook, subagent, toolcandidates = (*discover_scope(Scope("project", project_root)), *discover_scope(Scope("user", user_root)))immediate children onlycatalog = build_catalog(candidates, precedence=("project", "user"), budget=CatalogBudget(max_entries=10, max_catalog_chars=2_000))body = load_skill_body(selected, candidates)level 2reference = load_reference(selected, "references/format.md")level 3validate_reference(skill_directory, reference)blocks traversal and escaperoute_request(skills, request, adapter)eligibility before rankingbuild_invocation_matrix(policy)human by model viewRouter and installer (projects)#
const skills = await loadCatalog(root);SKILL.md plus routing.jsonrank(skills, query, files);keyword 2, path 3plan(skills, selected, allowed);dependencies firstroute(skills, query, files, allowed, margin = 1);ready, no-match, ambiguous, blockedsafePath(name);rejects .., absolute, C:, backslashconst files = translate(bundle, agent);new quoted header, same bodyconst expected = digest(bundle.files);SHA-256 of sorted pairsawait install(root, bundle, agent, expectedDigest);staged rename with backupHuman and model invocation#
| Factor | Shared | Human-only | Model-only | Disabled |
|---|---|---|---|---|
| Human can invoke | Yes | Yes | No | No |
| Model can invoke | Yes | No | Yes | No |
| One host field | Default | disable-model-invocation: true | user-invocable: false | Not defined |
| Example | Test planning | Publish preparation | Internal style guide | Deprecated package |
Limits and defaults#
| Setting | Default | Note |
|---|---|---|
name length | 64 | Lowercase words joined by hyphens |
description length | 1024 | Says what and when |
compatibility length | 500 | Optional core field |
max_description_chars | 240 | CatalogBudget per entry |
max_catalog_chars | 8_000 | CatalogBudget total |
max_chars | 12_000 | Body and reference loads |
model_threshold | 0.2 | Implicit selection floor |
Router margin | 1 | Smaller score gap is ambiguous |
Failures and fixes#
| Symptom | Cause | Fix |
|---|---|---|
no-match | No keyword or path scored | Add keywords or paths in routing.json |
ambiguous | Top two scores differ by less than margin | Make the trigger boundaries distinct |
blocked with permission denied | Skill or a dependency needs more permissions | Allow it or pick another route |
unsupported YAML syntax | Tag, alias, multiline or flow value | Use a plain or double-quoted scalar |
integrity mismatch | Bundle digest differs from the expected digest | Run inspect, compare source_digest |
modified installation | A tracked file changed since install | Move the edit into the source bundle |
| Skill unavailable after install | Host did not rescan its catalog | Start a new session or rescan, then retry |
| Model never picks the skill | Vague description or budget cut it | Check the discovery log and catalog size |