Skills¶
Agent skills framework for structured tool definitions. See the Agent Skills guide for usage examples.
Core¶
Skill
dataclass
¶
Full skill definition including instructions body.
read_reference ¶
Read a reference file by name.
Raises:
| Type | Description |
|---|---|
SkillPathError
|
If filename is not a plain name inside the skill's
|
FileNotFoundError
|
If the reference file does not exist. |
resolve_script ¶
Resolve a script inside the skill's scripts/ directory.
ScriptExecutor implementations should build their command from this
rather than joining the name themselves. Execution policy — sandboxing,
timeouts, allowed interpreters — stays the integrator's call, but which
file gets run should not depend on each integrator repeating the same
containment check.
Raises:
| Type | Description |
|---|---|
SkillPathError
|
If script_name is not a plain name inside the
skill's |
FileNotFoundError
|
If the script does not exist. |
SkillMetadata
dataclass
¶
SkillMetadata(name, description, license=None, compatibility=None, allowed_tools=None, extra_metadata=dict())
Lightweight metadata parsed from SKILL.md frontmatter.
allowed_tools
class-attribute
instance-attribute
¶
Tool access patterns this skill gates (RFC §24.2).
Both frontmatter forms are accepted: a YAML list, which is what the RFC's
own example uses, and a comma-separated scalar. Entries are ToolPolicy
globs, so search_* covers every tool whose name starts with search_.
required_tool_names
property
¶
Exact prerequisite names from the optional requires metadata.
These describe dependencies, not grants. Applications resolve skill availability against their authorized catalogue before using it.
gated_tool_names
property
¶
The patterns this skill gates, one per entry.
Accepts either frontmatter form. Returns an empty list when the field
is None or blank. The entries are patterns, not names — match them
with :meth:gates, never with in.
gates ¶
Whether this skill gates tool_name (RFC §24.2 glob semantics).
Uses the same fnmatch matching as :class:~roomkit.tools.policy.ToolPolicy,
so a skill and a policy agree on what a pattern covers.
ScriptResult ¶
Bases: BaseModel
Result of executing a skill script.
SkillRegistry ¶
Discover, load, and manage Agent Skills.
Lightweight metadata is parsed on discover/register. Full skill
instructions are loaded lazily on first get_skill() call and
cached for subsequent access.
requires_match says whether a skill's requires name is served
by the tools a conversation offers (RFC §24.3): an exact tool name by
default, a host's own reading otherwise (a hub served by any tool
named <hub>_*, say). Every door checks requires through it.
execution_tool_patterns
property
¶
The patterns of the host's tools that run code, named when its
servers were registered (execution_tools): gated like the sandbox's
while a served skill is active (RFC §24.7).
has_entries
property
¶
Whether the model has anything to be told: a skill it can activate, or one marked unavailable, whose reason it gives instead of guessing.
discover ¶
Scan directories for subdirectories containing SKILL.md.
A malformed skill is a deployment error, not a runtime condition, so the default is to stop. Skipping it instead removes the skill from the catalogue while the agent keeps answering: the model is never told the capability is missing, and neither is anyone reading the conversation. The failure surfaces hours later as an agent that quietly cannot do something it was configured to do.
Discovery commits only once every candidate has parsed, so a strict failure leaves the registry exactly as it was rather than half filled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directories
|
str | Path
|
Directories to scan. Only immediate subdirectories containing a SKILL.md are considered. |
()
|
strict
|
bool
|
Stop on the first unreadable directory or invalid skill. Set False to log and skip each instead — appropriate when skills come from a source you do not control. |
True
|
Returns:
| Type | Description |
|---|---|
int
|
The number of skills registered. |
Raises:
| Type | Description |
|---|---|
SkillDiscoveryError
|
In strict mode, when a directory cannot be scanned or a candidate escapes it through a symlink. |
SkillParseError
|
In strict mode, when a SKILL.md cannot be parsed. |
SkillValidationError
|
In strict mode, when metadata is invalid. |
register ¶
Register a single skill directory.
Parses frontmatter only (lightweight). Replaces any existing skill with the same name.
Raises:
| Type | Description |
|---|---|
SkillParseError
|
If SKILL.md cannot be found or parsed. |
SkillValidationError
|
If metadata fails validation. |
add ¶
Register a skill built in memory (a store, a marketplace), replacing any earlier one of the same name (RFC §24.3).
Its path is where its scripts and references are read from. Adding
it clears its marks, as registering a directory does. Logged at debug:
a store adds its whole catalogue at once, and says so itself.
Raises:
| Type | Description |
|---|---|
SkillValidationError
|
The name holds |
copy ¶
A registry of names, every registered skill when None (RFC §24.3).
It finds every skill the source finds, one discovered but not yet loaded included: each name keeps its path and, once loaded, its skill. With marks, the copy keeps the source's unlisted marks and the unavailable reasons of the names it copies; without, every skill it copies is available and listed (a hand-picked set, say), and a name the source marks unavailable is not copied at all, nor asked of its server.
add_mcp_server
async
¶
Register the skills an MCP server serves, under label (RFC §24.7).
Only the listing is read: a skill's SKILL.md is fetched when it is
activated, and checked then against the entry the listing gave. Each
skill is named <label>:<path> (hf:hf-cli). An entry the
extension does not allow, one past its limits, and a dynamic one
unless allow_dynamic are registered as unavailable with their
reason, the server's other skills staying usable. Registering a server
again replaces its entries: a skill it no longer offers, or offers in
a form this host does not take, retires; one it still offers keeps,
while loaded, the entry it was loaded from.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
server
|
MCPSkillServer
|
The connected server
(:class: |
required |
label
|
str
|
The host's name for the server: an identifier, never the name the server gives itself. |
required |
allow_dynamic
|
bool
|
Take skills whose content the server generates, which nothing can verify. |
False
|
approve_execution
|
ApproveExecution | None
|
Asked before a tool that runs code is served while one of this server's skills is active; without it, such a call is refused. |
None
|
execution_tools
|
Sequence[str]
|
Patterns of the host's own tools that run code, gated like the sandbox's. |
()
|
Returns:
| Type | Description |
|---|---|
int
|
How many of the server's skills are available. |
Raises:
| Type | Description |
|---|---|
SkillValidationError
|
label is not an identifier, or names another server already. |
SkillDiscoveryError
|
The server does not declare the extension, or its listing cannot be read. |
load_skill
async
¶
The skill name, loaded: what an activation reads (RFC §24.4).
A host's own skill is parsed as :meth:get_skill parses it. A skill
an MCP server serves is read from its server now, and checked against
its entry, unless it is loaded already: it then keeps the entry it was
loaded from (RFC §24.7). A <label>:<path> the listing did not
hold, under a label this registry registered (not a copy narrowed to
some names), is asked of its server with skills/get and kept out
of the manifest. A skill marked unavailable is never loaded, one
loaded before included, nor one the catalog this registry shares no
longer holds, or holds in a form this host does not take.
Raises:
| Type | Description |
|---|---|
SkillError
|
A served skill that is not found on its server, or whose content does not match its entry; the message names the skill only. |
read_file
async
¶
The text of filename, a file of skill name (RFC §24.6, §24.7).
A host's own skill reads a reference by name, confined to its
references/ directory. A served skill reads a path inside the
skill (templates/invoice.md) that the entry it was loaded from
lists, from its own server, checked against that entry; it must be
loaded (activated) first.
Raises:
| Type | Description |
|---|---|
KeyError
|
No skill name is loaded or found here. |
SkillPathError
|
The name escapes the skill, or is not one of a served skill's files (nothing is read then). |
FileNotFoundError
|
A host's skill has no such reference. |
SkillChangedError
|
A served skill's file failed verification, or the catalog this registry shares no longer holds the skill in a form this host takes: the skill is retired here and must be activated again. |
mark_unavailable ¶
Record a skill that exists but cannot be used in this context.
The skill leaves the available set entirely — skill_names,
all_metadata() and get_skill() no longer see it — and only
surfaces through unavailable_skills, the prompt manifest and
the skill-tool error paths, so callers can say WHY it is missing
instead of leaving a silent gap (e.g. a requires gate dropping
a skill whose tools are not granted in this execution context).
What it gated stays closed: no activation can open it any more
(:meth:gated_tool_names).
gated_tool_names ¶
The tool patterns skills keep closed (RFC §24.2): those of every
registered skill not in activated, and the closed ones
(:meth:closed_tool_names). Both doors read skill gating through
this one rule.
closed_tool_names ¶
The tool patterns only skills marked unavailable gate, which nothing can open (RFC §24.2). A pattern a skill in activated gates is that skill's to open: an unavailable skill gating the same pattern does not hold it closed.
unopenable_tool_names ¶
The closed patterns no available skill gates as well: no activation can open them (RFC §24.2).
mark_unlisted ¶
Keep name activatable but out of the prompt manifest.
The third visibility state, between available and unavailable: the
skill stays registered — activate_skill, get_skill() and
skill_names still see it — but to_prompt_xml() and
listed_names do not. For catalogues where advertising every
entry would drown the ones that matter: a host can keep quiet about
a skill while any path that names it (a recommender nudge, a user
asking for it) still activates it, which is what lets it earn its
listing back.
Unknown names are ignored — there is nothing to hide.
get_unavailable_reason ¶
Reason a skill is unavailable in this context, or None.
to_prompt_xml ¶
Generate spec-compliant
Skills marked unavailable are listed in a separate
<unavailable_skills> block with their reason, so the model
can explain the gap instead of guessing at a name that will
answer "not found". Skills marked unlisted are simply absent —
activatable, but not advertised. Content is HTML-escaped to
prevent injection.
ScriptExecutor ¶
Bases: ABC
Execute skill scripts with integrator-defined policy.
No default implementation is provided — the execution policy (sandboxing, timeouts, allowed interpreters) is always the integrator's responsibility.
execute
abstractmethod
async
¶
Run a script from a skill's scripts/ directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill
|
Skill
|
The skill that owns the script. |
required |
script_name
|
str
|
Filename of the script to run. |
required |
arguments
|
dict[str, str] | None
|
Optional key-value arguments to pass. |
None
|
Returns:
| Type | Description |
|---|---|
ScriptResult
|
Result of the script execution. |
RunSkillScriptTool ¶
Runs a skill's script, as run_skill_script, with executor.
Satisfies :class:roomkit.tools.Tool: the schema every channel declares
and the handler every channel calls. A script outside its skill answers
an error; a skill the registry does not offer refuses the call
(:class:~roomkit.core.exceptions.ToolRefusedError), as on any channel.
Served over MCP¶
Skills an MCP server publishes under the MCP Skills extension. See the Skills over MCP guide.
MCPSkill
dataclass
¶
MCPSkill(metadata, instructions, path, origin='', entry=None, files=dict(), read_total=0, retirements=0)
Bases: Skill
A skill whose SKILL.md an MCP server served and the registry verified.
It holds the entry it was loaded from for as long as it is loaded: every
file it reads is one that entry lists, checked against it. Nothing of it
is on disk: its files are read through
:meth:~roomkit.skills.SkillRegistry.read_file, never through path,
and it has no script a host can run.
origin
class-attribute
instance-attribute
¶
The host's label for the server that serves it.
files
class-attribute
instance-attribute
¶
The bytes of each file read so far, verified, by URI.
read_total
class-attribute
instance-attribute
¶
Bytes read so far: what bounds a dynamic skill, which lists no sizes.
retirements
class-attribute
instance-attribute
¶
How many times a failed check had retired its name when it was loaded: a later one retires it in every registry holding it.
list_references ¶
Every file its entry lists but SKILL.md, as a path inside the
skill; none for a dynamic skill, which lists nothing.
read_reference ¶
Refused: a served skill's file is read from its server, verified,
through :meth:~roomkit.skills.SkillRegistry.read_file.
resolve_script ¶
Refused: a served skill's files are never written to disk to be run.
SkillExecutionRequest
dataclass
¶
What a host is asked before a tool that runs code is served while a skill an MCP server serves is active in the conversation.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The skill's name in the registry ( |
label |
str
|
The host's label for the server that serves it. |
uri |
str
|
The URI of the skill's |
fingerprint |
str | None
|
The SHA-256 of the skill's files' URIs and digests,
sorted (:attr: |
room_id |
str | None
|
The conversation the skill is active in. |
tool |
str
|
The tool about to run code. |
ServedOrigin
dataclass
¶
A server a host registered skills from, under the host's label for it.
MCPSkillServer ¶
Bases: Protocol
The three things a registry asks of a connected MCP server.
:class:~roomkit.tools.mcp.MCPToolProvider is one. Nothing here relies on
a session: a skill's identity, the entry it was loaded from and the content
verified are the registry's, so a transport without a session serves them
alike.
SkillChangedError ¶
Bases: SkillVerificationError
A file of an active served skill failed verification: the skill is retired, its entry read again, and it must be activated again.
SkillVerificationError ¶
Bases: SkillError
Content an MCP server served for a skill does not match its entry: a length, a digest, a frontmatter, or a file the entry does not list (RFC §24.7). The content is not used.
Exceptions¶
SkillParseError ¶
Bases: SkillError
Failed to parse SKILL.md content.
SkillValidationError ¶
Bases: SkillError
SKILL.md metadata failed validation.