Register skills
Register Markdown playbooks in a SkillCatalog and surface them through search_capabilities alongside tools.
Skills are Markdown playbooks (a deploy runbook, a debugging checklist) ranked by a separate BM25 corpus from tools. What a skill is and when to reach for one is on Tools vs MCP vs skills; Ratel's own coding-agent skills — including ratel-decompose-prompt, which extracts skills from a long system prompt — are on the Quick start.
Register a skill
from ratel_ai import Skill, SkillCatalog, get_skill_content_tool, search_capabilities_tool
skills = SkillCatalog()
skills.register(
Skill(
id="vercel-deploy",
name="vercel-deploy",
description="How to deploy to Vercel: env vars, preview vs production, rollbacks.",
tags=["deploy", "ship to production"], # indexed for ranking
tools=["vercel__deploy", "fs__read_file"], # surfaced alongside the skill when it matches
metadata={"stacks": ["next", "vercel"]}, # non-indexed context for higher-layer ranking
body="## Deploying to Vercel\n1. ...", # returned by get_skill_content_tool
)
)
search = search_capabilities_tool(catalog, skills) # 2nd arg → result gains a populated `skills` bucket
load = get_skill_content_tool(skills) # id == "get_skill_content"Only id, name, and description are required; tags, tools, metadata, and body are optional. get_skill_content({skillId}) returns {"body": ...}, or {"error": ..., "isError": True} for an unknown id.
How skills surface
Pass a SkillCatalog as the second argument to search_capabilities_tool and search returns the skills bucket alongside tools, each with its own result budget, so a relevant skill is never starved by matching tools. The agent pulls a skill's full body into context on demand via get_skill_content_tool (id get_skill_content, constant GET_SKILL_CONTENT_ID).
A skill can also declare the tools its instructions call: when the skill matches a query, those tools are pulled into the tools bucket (additively, deduped) so the agent gets the playbook and the tools it needs in one turn instead of a second search.
The SkillCatalog surface
SkillCatalog(trace=None, method="bm25") takes the same constructor keywords as ToolCatalog, and its method surface mirrors it over the skill corpus:
skills.search(query, top_k) # → list[SkillHit] (.skill_id, .score); origin=, method= as on ToolCatalog
skills.has(skill_id) # → bool
skills.get(skill_id) # → Skill | None
skills.size() # → int
skills.invoke(skill_id) # → str: the body; raises ValueError on an unknown idbuild_embeddings(), record_event(), and drain_trace_events() work exactly as on ToolCatalog. Note that invoke is synchronous here, no await: loading a skill body is a lookup, not an executor call. It records a skill_invoke trace event.
Embeddings for skills
The skill corpus has its own embedding cache, maintained exactly like the tool one (Build the embedding cache): construct SkillCatalog with method="semantic" or "hybrid" to embed eagerly at register, or keep the BM25 default and call skills.build_embeddings() before opting in per call. The two caches are independent — skills can rank hybrid while tools stay on BM25.
Embeddings cover the same projection the ranking indexes — name, description, tags — never the body, so a long playbook costs one small embedding. When the engines are worth it is on Semantic & hybrid search.
Next steps
Register MCP servers
Ingest an upstream MCP server's tools with register_mcp_server: namespaced ids, the session-owning handle, error propagation, one ranked surface.
Use the discovery tools
Hand the agent search_capabilities, invoke_tool, and get_skill_content, then assemble each turn's toolset with a top-K pre-filter.